12.2 핵심 웹 지표란?
핵심 웹 지표는 구글에서 만든 지표로, 웹사이트에서 뛰어난 사용자 경험을 제공하는 데 필수적인 지표를 일컫는 용어다.
구글에서 핵심 웹 지표로 꼽는 지표는 아래와 같다.
최대 콘텐츠풀 페인드 (LCP : Largest Contentful Paint)
최초 입력 지연 (FID : First Input Delay)
누적 레이아웃 이동 (CLS : Cumulative Layout Shift)
핵심 지표는 아니지만 특정 문제를 진단하는 데 사용될 수 있는 지표 두개는 아래와 같다.
최초 바이트까지의 시간(TTFB : Time To First Byte)
최초 콘텐츠풀 시간(FCP : First Contentful Paint)
12.3 최대 콘텐츠풀 페인트 (LCP)
12.3.1 정의
최대 콘텐츠풀 페인트란
‘페이지가 처음으로 로드를 시작한 시점부터 뷰포인트 내부에서 가장 큰 이미지 또는 텍스트를 렌더링하는 데 걸리는 시간’ 을 말한다.
뷰포트는 사용자에게 현재 노출되는 화면을 의미한다.
<img>
<svg> 내부의 <image>
poster 속성을 사용하는 <video>
url()을 통해 불러온 배경 이미지가 있는 요소
이 블록 레벨 요소에는 <p>, <div> 등이 포함된다.
즉, 사용자의 기기가 노출하는 뷰포트 내부에서 가장 큰 영역을 차지하는 요소가 렌더링되는 데 얼마나 걸리는지를 측정하는 지표인 것이다.
12.3.4 기준 점수
최대 콘텐츠풀 페인트에서 좋은 점수란 해당 지표가 2.5초 내로 응답이 오는 것이다. 4초 이내로 응답이 온다면 보통, 그 이상이 걸리면 나쁨으로 판단된다.
12.3.5 개선방안
텍스트는 언제나 옳다.
아무리 이미지를 최적화 하더라도 같은 크기 내에 텍스트가 이미지보다 리소스가 적게 들어가기 때문에 이미지를 텍스트로 대체한다면 좋은 지표를 얻을 수 잇따.
이미지는 어떻게 불러올 것인가?
사용자에게 더 강렬한 인상을 주기 위해 아무래도 텍스트보다는 이미지를 사용하기를 원할 것이다. 이때 개발자가 선택할 수 있는 이미지를 노출하는 방법에는 다음과 같이 여러가지가 있다.
<img src={}>
<svg>
<image href={}/>
</svg>
<video poster=''/>
<div style='background-image:url()'>
위의 네 가지 방법을 시간별로 스크린샷을 찍어서 보면 1번과 3번의 코드가 더 빠르게 완성되는 것을 볼 수 있다.
<img>
이미지는 브라우저의 프리로드 스캐너에 의해서 먼저 발견되어 빠르게 요청이 일어난다. 프리로드 스캐너란 HTML을 파싱하는 단계를 차단하지 않고 이미지와 같이 빠르게 미리 로딩하면 좋은 리소스를 먼저 찾아 로딩하는 브라우저의 기능이다.
<svg>
모든 리소스를 다 불러온 이후에 이미지를 불러온다.
<video poster=’’>
poster는 사용자가 video 요소를 재생하거나 탐색하기 전까지 노출되는 요소다.
이 역시 img 와 같이 프리로드 스캐너에 의해 조기에 발견되어 <img>와 같은 성능을 나타낸다. poster가 없는 경우에는 video를 실제로 로딩해 첫 번째 프레임을 해당 poster 리소스로 대체한다. 따라서 video가 최대 콘텐츠풀 페인트에 영향을 받을 것 같다면 poster를 반드시 넣어주는 것이 좋다.
<div background-image>
css에 있는 리소스는 항상 느리다. 이러한 리소스는 브라우저가 해당 리소스를 필요로 하는 DOM을 그릴 준비가 될 때까지 리소스 요청을 뒤로 미루기 때문이다.
따라서 가능하다면 background-image는 최대 콘텐츠풀 페인트와 같이 중요한 리소스에는 사용하지 않는 것이 좋다.
그 밖의 조심해야 할 사항
이미지 무손실 압축 : 웹으로 서비스할 이미지는 가능한 한 무손실 형식으로 압축해 최소한의 용량으로 서비스하는 것이 좋다.
loading = lazy 주의 : 리소스를 중요하지 않음으로 표시하고 필요할때만 로드하는 전략인데 문제는 최대 콘텐츠풀 콘텐츠의 이미지는 중요하지 않은 리소스로 분류해서는 안된다는 것이다. 따라서 상대적으로 중요하지 않은 이미지에서는 사용해도 좋지만 최대 콘텐츠풀 콘텐츠의 이미지에는 사용하지 않는 것이 좋다.
fadein 과 같은 각종 애니메이션 : 이미지가 그냥 뜨는 것보다 fadeIn ease 10s 와 같이 처리한다면 최대 콘텐츠풀 페인트도 그만큼 늦어진다.
12.4 최초 입력 지연 (FID)
12.4.1 정의
웹페이지의 로딩속도가 아닌 웹사이트의 반응속도를 말한다.
이러한 웹사이트의 반응성을 측정하는 지표가 바로 최초 입력 지연이다.
사용자가 페이지와 처음 상호 작용할 때 부터 해당 상호 작용에 대한 응답으로 브라우저가 실제로 이벤트 핸들러 처리를 시작하기까지의 시간을 측정한다.
구글에서 정의한 네가지 사용자 경험 (RAIL)
Response : 사용자의 입력에 대한 반응 속도, 50ms 미만으로 이벤트를 처리할 것
Animation : 애니메이션 각 프레임을 10ms 이하로 생성할 것
Idle : 유휴 시간을 극대화해 페이지가 50ms 이내에 사용자 입력에 응답하도록 할 것
Load : 5초 이내에 콘텐츠를 전달하고 인터랙션을 준비할 것
이 중 최초 입력 지연은 R에 해당하는 응답에 초점을 맞추고 있다.
12.4.4 기준점수
최초 입력 지연의 좋은 점수를 얻기 위해서는 100ms 이내로 응답이 와야 하며, 300ms 이내인 경우 보통, 그 이후는 나쁨으로 처리된다.
12.4.5 개선 방안
최초 입력 지연을 개선하기 위해서는 최초 입력 지연에 가장 큰 영향을 미치는 메인 스레드에 이벤트를 실행할 여유를 줘야한다.
실행에 오래걸리는 긴 작업을 분리
‘긴 작업’이란 실행을 완료하는데 오래걸리는 작업을 의미한다.
메인 스레드가 처리에 오래 걸리는 작업이 있으면 긴 작업이 있다는 경고가 뜬다.
이러한 긴 작업은 최초 입력 지연 뿐만 아니라 웹페이지 전반에 악영향을 미치기 때문에 대안을 연구해야 한다.
꼭 웹페이지에서 해야하는 작업인가
유저의 기기는 개발자보다 좋지 않을 확률이 높기 때문에 만일 너무 오래 걸리는 작업이라면 서버로 옮겨서 처리하는 것이 좋디.
긴 작업을 여러 개로 분리하기
꼭 웹페이지에서 처리해야하는 작업이라면 메인 스레드를 계속 점유할 수록 사용자는 페이지에서 응답을 받지 못하고 있을 확률이 크다.
자바스크립트 코드 최소화
크롬 개발자 도구로 들어가서 커버리지를 클릭 후 기록한 뒤에 웹페이지를 새로고침하자. 이렇게 기록을 해주면 웹페이지에서 사용되지 않은 코드가 얼마나 있는지 확인할 수 있다.
하지만 이곳에 표시된 모든 코드들이 필요없는 코드라는 것은 아니며 이 중에는 사용자의 특정 이벤트에 따라 실행되는 코드, 예기치 못한 상황에서 실행될 코드 등 다양한 것들이 존재할 수 있다.
타사 자바스크립트 코드 실행의 지연
Google Analytics 나 Firebase 같이 웹페이지의 통계 집계를 위해 제3자가 만든 타사 스크립트를 넣는 경우가 있는데 이러한 코드는 대부분 웹페이지 로드에 중요한 자원이 아니므로 async 와 defer를 이용해 지연 불러오기를 하는 것이 좋다.
defer : script에 defer속성이 있다면 먼저 해당 스크립트를 다른 리소스와 함께 병렬로 다운로드 한다. 다운로드가 완료되었다 하더라도 이 스크립트의 실행은 페이지가 완전히 로딩된 이후에 맨 마지막에 실행된다.
async : script에 async 속성이 있다면 해당 스크립트를 다른 리소스와 함께 병렬로 다운로드 한다. async 리소스의 다운로드가 완료되어 버리면 다른 리소스의 다운로드가 완료를 기다리지 않고 바로 실행된다.
둘다 없는 경우 : script를 만나는 순간 다운로드가 우선되며, 다운로드가 완료되면 코드 실행이 우선된다. 다른 작업은 다운로드와 실행이 끝날 때까지 미뤄진다.
없는경우 , async, defer 뒤로 갈 수록 실행은 뒤로 미뤄지지만 성능은 좋아진다. 따라서 타사 자바스크립트는 가능하면 async를, 더 가능하다면 defer로 지연하는 것이 좋다.
12.5 누적 레이아웃 이동 (CLS)
12.5.1 정의
페이지의 생명주기 동안 발생하는 모든 예기치 않은 이동에 대한 지표를 계산하는 것이 바로 누적 레이아웃 이동 이라고 한다.
ex) 무언가를 클릭하려 했으나 뒤늦은 로딩으로 인해 클릭 하려 했던 버튼이 아니라 다른 부분을 클릭하는 경우
12.5.4 기준 점수
누적 레이아웃 이동의 경우 0.1 이하인 경우 좋음, 0.25 이하인 경우 보통이며 그 외에는 개선이 필요한 나쁜 점수로 보고된다.
12.5.5 개선방안
삽입이 예상되는 요소를 위한 추가적인 공간 확보
useEffect의 내부에서 요소에 영향을 미치는 작업, 특히 뷰포트 내부에서 노출될 확률이 높은 작업을 최소화 하는 것이 좋다. useEffect 사용이 불가피 하다면 useLayoutEffect 훅 사용을 고려해 볼 수 있겠지만 useLayoutEffect는 동기적으로 발생해 브라우저의 페인팅 작업에 영향을 미치기 때문에 로딩이 오래 걸리는 것과 같이 보일 수 있다.
스켈레톤 UI의 사례 처럼 미리 무언가가 동적으로 뜰 것으로 예상되는 공간을 미리 확보해 두는 것도 좋은 방법이다.
하지만 가장 좋은 방법은 역시 서버사이드 렌더링이다.
서버에서 이러한 동적인 요소의 유무를 사전에 판단해 클라이언트에 HTML을 미리 제공해 준다면 클라이언트에서는 이런 고민 없이 깔끔하게 처리할 수 있다.
폰트 로딩 최적화
폰트로 발생할 수 있는 문제는 두 가지 인데
FOUT(flash of unstyled text) : HTML문서에서 지정한 폰트가 보이지 않고 대체 기본 폰트로 보이고 있다가 뒤늦게 폰트가 적용되는 현상
FOIT(flash of invisible text) : HTML 문서에서 지정한 폰트가 보이지 않고, 기본 폰트도 없어서 텍스트가 없는 채로 있다가 뒤늦게 폰트가 로딩되면서 페이지에 렌더링 되는 현상
<link>의 preload 사용
<link> 의 rel=preload는 페이지에서 즉시 필요로 하는 리소스를 명시하는 기능이다.
preload로 지정된 요소는 웹페이지의 생명주기에서 초기에 불러와야하는 중요한 리소스로 간주되므로 브라우저는 리소스를 더 빠르게 준비해준다.
font-family : optional : 폰트를 불러올 수 있는 방법은 크게 다섯 가지로 나뉜다.
auto : 브라우저가 폰트를 불러오는 방법을 결정
swap : FOUT 방식이다. 폴백 폰트로 글자를 렌더링 후, 웹폰트 로딩이 완료되면 웹 폰트 적용
fallback : 이 옵션을 선택하면 100ms간 텍스트가 보이지 않고, 그 이후 폴백 폰트로 렌더링한다. 그리고 3초 안에 폰트가 로딩된다면 웹 폰트로 전환되고, 그렇지 않다면 폴백폰트로 유지된다.
optional : 100ms간 텍스트가 보이지 않고 그 이후 폴백 폰트로 렌더링한다. 그러나 0.1초 내로 폰트가 다운로드돼있거나 캐시돼 있지 않다면 폴백 폰트를 사용한다.
또한 브라우저가 네트워크 상태를 파악해 일정 기간 폰트를 다운로드 하지 못하면 연결을 취소한다.
적절한 이미지 크기 설정
width : 100% , height : auto 는 반응형에서 흔히 쓰이는 방식이지만 이미지 로딩에 의해 레이아웃 이동이 크게 발생한다는 단점이 있다. 이를 해결하는 가장 좋은 방법은 비율을 함께 사용하는 것이다. width : 100%, height : auto 와 함께 , <img>태그에 가로 세로 비율을 적어 놓는다면 브라우저가 이미지를 로딩하기 전에 적절한 비율을 계산해 이미지가 표시되는 만큼 면적을 할당해 둔다.