웹 성능 지표
웹 성능 지표에는 어떤 것들이 있을까?
가장 유명하고 자료도 가장 방대한 라이트하우스를 기준으로 웹성능 지표를 학습해보고자 한다. 성능 말고도 접근성, PWA, SEO에 대한 측정도 가능하다고 한다.
아래는 라이트하우스에서 측정 기준에 대한 가중치를 나타낸 표이다 (버전 10기준). 들어본 지표도 있고, 처음 보는 지표도 있다. 하나하나 조금씩 알아가보자.
FCP (First Contentful Paint)
FCP는 사용자가 페이지로 이동한 후 브라우저가 첫 번째 DOM 컨텐츠를 렌더링하는 데 걸리는 시간을 측정한다. 페이지의 이미지, 흰색이 아닌 <canvas>, SVG는 DOM 컨텐츠로 간주되면 iframe 안의 모든 요소는 포함되지 않는다.
참고로 라이트하우스는 HTTP 아카이브의 실제 데이터를 기반으로 성능 지표를 정한다. 아래 이미지는 FCP 측정에 관한 표다. 대략 1.2초인 경우 만점에 가까운 점수를 받고, 1.8초 이내일 경우 좋은 평가를 받을 수 있다.
FCP를 향상시키는 방법은 다양하지만 특히 중요한 문제 중 하나는 폰트 로드 시간이다.
LCP (Largest Contentful Paint)
LCP는 뷰포트에서 가장 큰 콘텐츠 요소가 화면에 렌더링되는 시점을 측정한다. 이는 페이지의 주요 컨텐츠가 사용자에게 표시되는 시점을 대략적으로 나타낸다.
LCP 측정에 관한 표를 살펴보면 2.5초 이내일 경우 좋은 평가를 받을 수 있다.
어떤 요소들을 LCP에서 측정할까?
- <img> 엘리먼트 (gif나 animated PNG의 경우 첫 프레임이 나타나는 시간 기준)
- <svg>안에 사용된 <image> 엘리먼트
- <video> 엘리먼트 (첫 프레임이 나타나는 시간 기준)
- url() 함수를 이용하여 배경 이미지가 로드된 요소 (CSS gradient 제외)
- 블록 레벨 엘리먼트
참고로, LCP가 측정하는 요소의 크기는 뷰포트 내에서 사용자에게 표시되는 크기다. 오버플로가 있는 경우 해당 부분은 요소의 크기에 포함되지 않는다. 이미지 요소의 경우 표시되는 크기와 고유 크기 중 더 작은 크기이며, 텍스트 요소의 경우 모든 텍스트 노드를 포함할 수 있는 가장 작은 사각형만 고려한다. 모든 요소에 대해 LCP는 margin, padding, border를 고려하지 않는다.
LCP는 어떻게 향상시킬 수 있을까? LCP가 이미지인 경우, 타이밍은 4단계로 나눌 수 있다. 어떤 단계가 가장 오래 걸리는지 알면 LCP를 최적화하는 데 도움이 될 수 있다.
첫번째 단계는 TTFB로, 사용자가 페이지 로드를 시작한 시점부터 브라우저가 HTML 문서 응답의 첫 바이트를 수신할 때까지의 시간이다.
두번째 단계는 TTFB와 브라우저가 LCP 리소스를 로드하기 시작하는 시점 사이의 차이다.
세번째 단계는 LCP 리소스 자체를 로드하는 데 걸리는 시간이다.
네번째 단계는 리소스 로딩이 완료된 시점부터 LCP 요소가 완전히 렌더링될 때까지의 지연 시간이다.
각 단계에 대한 상세한 최적화는 이 링크에서 확인할 수 있다. 하나 눈 여겨 볼 점은 render delay를 줄이기 위해 ssr과 ssg를 권장하고 있다.
CLS (Cumulative Layout Shfit)
CLS는 페이지 수명 동안 발생하는 모든 예상하지 못한 layout shift에 대해 가장 큰 layout shfit 점수를 측정한 것이다. 일반적으로 리소스가 비동기적으로 로드되거나 DOM 요소가 기존 컨텐츠보다 먼저 페이지에 동적으로 추가될 때 발생한다.
CLS의 경우 0.1 미만일때 좋은 평가를 받는다.
CLS를 측정 하는 방법은 web dev에 아주 잘 나와있는데 간략히 설명하자면, 뷰 포트에서 layout shift가 발생하는 영역(impact fraction)과 layout shift로 발생한 거리(distance fraction)의 곱으로 이루어진다.
web dev에는 CLS를 최적화 하는 방법 역시 잘 나와있다. 정말 간략히 정리해보면 다음과 같다.
1. 이미지의 dimension (width,heignt)을 항상 포함할 것.
2. 광고, 임베드 등 로드가 느리게 되는 컨텐츠의 공간을 미리 확보하고, 불가능하다면 뷰포트의 후반부에 위치시키는 등 문서의 layout shift를 최소화할 것.
3. reflow와 repaint를 일으키는 css 속성 대신 composition만 일으키는 css 속성을 활용할 것.
4. font의 경우 대체 폰트 등 best practice를 따를 것.
Speed Index
speed index는 페이지 로딩 중 컨텐츠가 시각적으로 얼마나 빨리 표시되는지를 측정한다. 라이트 하우스는 브라우저에 페이지가 로딩되는 동영상을 캡처하여 프레임 사이의 시각적 진행 상황을 계산한다.
speed index의 경우 3.4초 이하일 경우 좋은 평가를 받는다.
페이지 로딩 속도를 개선하기 위해 수행하는 모든 작업은 speed index 점수를 향상시킨다. 하지만 라이트하우스에서 진단해준 문제를 해결하면 특히 큰 효과를 볼 수 있다.
1. 메인 스레드 작업 최소화.
2. 자바스크립트 실행 시간 단축.
3. 웹폰트 로드 중 텍스트가 계속 표시되도록 보장.
이에 대한 자세한 내용은 라이트하우스 문서에서 찾아볼 수 있다.
TTI (Time to Interactive)
사실 TTI는 라이트하우스 10 지표에서 제거되었다. 하지만 후에 살펴볼 Total Blocking Time에서 언급되고 있으므로 간단히 살펴보자.
TTI는 페이지가 완전히 인터랙티브한 상태가 되는 데 걸리는 시간을 측정한다. 페이지가 완전히 인터랙티브한 것으로 간주되는 시점은 다음과 같다.
- 페이지에 유용한 컨텐츠가 표시된다. (이는 FCP로 측정된다.)
- 사용자가 볼 수 있는 엘리먼트에 대해 이벤트 핸들러가 등록되어 있고, 페이지가 50ms 이내에 사용자 상호 작용에 응답한다.
TBT(Total Blocking Time)
TBT는 마우스 클릭, 화면 탭 또는 키보드 입력과 같은 사용자 입력에 대해 페이지가 응답하지 못하도록 차단된 총 시간을 측정한다. 이는 FCP와 TTI 사이에서 50ms 이상의 long task의 blocking portion을 더해서 측정한다. long task는 50ms 이상의 긴 작업을 말하며, blocking porition은 50ms 이후의 시간 (70ms라면 20ms)을 말한다.
TBT는 200ms 이내일 경우 좋은 평가를 받는다.
long task를 식별하는 방법은 web dev에 나와있다.
일반적으로 long task는 다음과 같다.
1. 불필요한 자바스크립트 로딩, 파싱, 실행. 메인스레드가 페이지를 로드하는 데 실제로 필요하지 않은 작업을 수행하는 것을 Performance 패널에서 발견할 수 있다. 코드 스플리팅을 통해 페이로드를 줄이거나, 사용하지 않는 코드를 제거하거나, 써드파티 Javascript를 효율적으로 로드하면 TBT 점수가 향상된다.
2. 비효율적인 자바스크립트 문. 예를 들어 Performance 패널에서 코드를 분석한 후 2000개의 노드를 반환하는 document.querySelectorAll('a')에 대한 호출이 있다고 가정해 보자. 10개 노드만 반환하는 보다 구체적인 selector를 사용하도록 코드를 리팩터링하면 TBT 점수가 향상될 수 있다.
추가적으로..
FCP, LCP, TTI, CLS, speed Index, TBT등을 살펴보았다. 하지만 CSR과 SSR, SSG에서 언제 FCP와 LCP, TTI가 발생하는지 조금 헷갈려서 찾아보니 해외 블로그 글에서 적절한 시각 자료를 찾아, 첨부한다.