모든 웹 개발자가 관심을 가져야 할 핵심 웹 지표

Nochi·2024년 1월 25일
1

Front-End

목록 보기
3/3

(리액트 딥다이브 12장 정리)

사용자가 웹 사이트에 접속했을 때 공통적으로 기대하는 사항

  • 방문한 목적을 손쉽게 달성할 수 있어야 한다.
  • 첫번째 목적을 달성하는데 걸리는 시간이 짧아야 한다.
  • 웹사이트에서 개인정보가 누출되는 등의 사고 없이 보안이 철저해야 한다.

이 외에는 어떻게 만들었든지 고객들에게 전혀 중요하지 않다. 리액트가 아무리 좋은 프레임워크라고 해도 웹 사이트의 성능이 뒤떨어진다면 이용자들의 호응을 얻기란 힘들다. 사용자가 느끼는 성능이 제일 중요하다.

웹 사이트 성능과 사용자 경험 사의 상관관계 (2019년 디지털 마케팅 에이전시 회사인 Protent의 조사)

  • 1초 내로 로딩되는 사이트는 5초 내로 로딩되는 사이트보다 전자상거래 전환율(실제 구매로 이어지는 고객의 비율)이 2.5배 더 높다.
  • 0~5초의 범위에서, 1초 로딩이 늦어질수록 전환율을 4.42%씩 떨어진다.
  • 페이지 로드 시간이 0~2초 사이인 페이지에서 가장 높은 전환율을 달성할 수 있다.
  • 소비자의 70%는 페이지 속도가 온라인 커머스 사이트를 방문하는데 영향을 미친다.
  • 절반 가까운 사람이 더욱 빠르게 로딩할 수 있다면 애니메이션과 동영상이 필요 없다.

구글에서 웹 사이트의 성능에 관한 통계

  • 전체 웹페이지를 표시하는데 필요한 최적의 평균 리소스 요청 수는 50회 미만이다. (즉, 한 페이지 로딩하는데 50회 미만의 요청이 발생해야 한다.)
  • 평균적으로 웹 페이지 전체를 요청하는데 15.3초가 걸린다.
  • 인간의 뇌와 신경계를 분석한 결과, 페이지 로드 시간이 1초에서 10초로 늘어날수록 모바일 사이트에서 이탈률이 123% 증거한다.

방문자들은 그다지 인내심이 많지 않다. 웹페이지 성능 또한 개발자의 책임이며, 웹사이트의 성능은 조직이 이루고자 하는 목표와 직결된다고 봐도 무방하다.

핵심 웹 지표(Core Web Vital)란

핵심 웹 지표

  • 최대 콘텐츠풀 페인트(LCP: Largest Contentful Paint)
  • 최초 입력 지연(FID: First Input Delay)
  • 누적 레이아웃 이동(CLS: Cumulative Layout Shift)

특정 문제를 진단하는데 사용될 수 있는 지표

  • 최초 바이트까지의 시간(TTFB: Time To First Byte)
  • 최초 컨텐츠풀 시간(FCP: First Contantful Paint)

최대 콘텐츠풀 페인트(LCP)

정의

  • 페이지가 처음으로 로드를 시작한 시점부터 뷰포트 내부에서 가장 큰 이미지 또는 텍스트를 렌더링하는데 걸리는 시간

각 엘리먼트가 등장한 시점부터 텍스트 또는 이미지가 완전히 로딩되는 시점

사용자의 기기가 노출하는 뷰포트 내부에서 가장 큰 영역을 차지하는 요소가 렌더링되는데 얼마나 걸리는지를 측정하는 지표인 것이다.

의미

단순히 사용자에게 로딩이란 뷰포트 영역에 보이는 부분을 기준으로 메인 컨텐츠가 화면에 완전히 전달되는 속도를 기준으로 하는데 사용자에게 페이지 정보를 화면에 전달하는 속도를 객관적으로 판단하기 위한 지표로 만들어진 것이 바로 LCP이다.

기준 점수

LCP 에서 좋은 점수란 해당 지표가 2.5 내로 응답이 오는 것이다.

  • 2.5초 이내: 좋음
  • 4초 이내: 보통
  • 그 이상: 나쁨

개선 방안

텍스트는 언제 옳다.

LCP 지표에 이미지가 아닌 문자열을 넣는게 확실히 더 빠르다. 가능한 한 텍스트로 채우는 것이 좋다.

이미지는 어떻게 불러올 것인가?

개발자가 선택할 수 있는 이미지 노출 방법

// img
<img src="lcp.jpg" ... />

// svg
<svg xmlns="http://www.w3.org/1000/svg">
	<image href="lcp.jpg" />
</svg>

// video.poster 
<video poster="lcp.jpg"></video>

// background-image: url()
<div style="background-image: url(lcp.jpg)">...<div/>
  • img: 이미지는 브라우저의 프리로드 스캐너에 의해서 먼저 발견되어 빠르게 요청이 일어난다.
  • svg 내부의 img: 모든 리소스를 다 불러온 이후에 이미지를 불러온다는 점이 img와 다르다. 즉, svg 내부의 img는 프리로드 스캐너에 의해 발견되지 않아 병렬적으로 다운로드가 일어나지 않는다. 고로 LCP 점수에 좋지 않다.
  • video의 poster: poster는 사용자가 video 요소를 재생하거나 탐색하기 전까지 노출되는 요소이며, 프리로드 스캐너에 의해 조기 발견되어 img와 같은 성능을 타나낸다.
  • “background-image: url()”: CSS에 있는 리소스는 항상 느리다. 이러한 리소스는 브라우저가 해당 리소스를 필요로 하는 DOM을 그릴 준비가 될 때까지 리소스 요청을 뒤로 미루기 때문이다. 그러므로 LCP에도 좋지 않기에 사용하지 않는 것이 좋다.

그 밖에 조심해야 할 사항

  • 이미지 무손실 압축: 가능한 무손실 형식으로 압축해서 최소한의 용량으로 서비스하기
  • loading=lazy 주의: loading=lazy는 리소스를 중요하지 않음으로 표시하고 필요할 때만 로드하는 전략임이어서 로딩 속도만 늦출 뿐 점수에 도움이 되지 않는다.
  • fadein과 같은 각종 애니메이션: 애니메이션 처리를 하는 동안 LCP도 늦어진다.
  • 클라이언트에서 빌드하지 말 것: 클라이언트에서 데이터를 로드에서 이미지를 뿌리는 행위
  • LCP 리소스는 직접 호스팅: 가능하다면 LCP 리소스는 같은 도메인에서 직접 호스팅하는 것이 좋다. 다른 출처에서 정제한 이미지를 가져오는 것은 최적화에 좋은 영향을 주지 않는다. 새로운 출처의 경우 네트워크 커넥션부터 다시 수행해야 하기 때문이다.

최초 입력 지연(FID)

정의

사용자가 페이지와 처음 상호 작용할 때부터 해당 상호 작용에 대한 응답으로 브라우저가 실제로 이벤트 핸들러 처리를 시작하기까지의 시간을 측정한다.

사용자가 얼마나 빠르게 웹페이지와 상호작용에 대한 응답을 받을 수 있는지 측정하는 지표이다. 최초의 입력 하나에 대해서만 그 응답 지연이 얼마나 걸리는지 판단한다.

의미

웹사이트 내부의 이벤트 반응이 늦어지는 이유는 브라우저의 메인 스레드가 바쁘기 때문이다. 바쁜 이유는 대규모 렌더링이 일어나거나 대규모 JS 파일을 분석하고 실행하는 등 다른 작업을 처리하는데 리소스를 할애하고 있기 때문이다.

메인 스레드가 바쁜 경우, JS 실행 환경은 ‘싱글 스레드’이기 때문에 자바스크립트가 이벤트 리스너와 같은 다른 작업을 실행할 수 없어 지연이 발생한다.

FID를 이해하기 위해 알아야 할 것은 ‘사용자의 입력’이다. 반응성에 해당하는 클릭, 터치, 타이핑 등 사용자의 개별 입력에 초점을 맞추고 측정한다.

구글은 사용자 경험을 크게 4가지로 분류하는데 이를 RAIL이라고 한다.

  • Response: 사용자의 입력에 대한 반응 속도, 50ms 미만으로 이벤트를 처리할 것
  • Animation: 애니메이션의 각 프레임을 10ms 이하로 생성할 것
  • Idle: 유휴 시간을 극대화해 페이지가 50ms 이내에 사용자 입력에 응답하도록 할 것
  • Load: 5초 이내에 콘텐츠를 전달하고 인터렉션을 준비할 것

이 가운데 FID는 R에 해당하는 응답에 초점을 맞추고 있다.

FID란 화면이 최초로 그려지고 난 뒤, 사용자가 웹페이지에서 클릭 등 상호작용을 수행했을 때 메인 스레드가 이벤트에 대한 반응을 할 수 있을 때까지 걸리는 시간을 의미한다. 그리고 이 시간은 메인 스레드가 처리해야 하는 다른 작업이 많을수록 느려진다.

기준 점수

  • 100ms 이내 : 좋음
  • 300ms 이내: 보통
  • 이후 : 나쁨

개선 방안

메인 스레드에 이벤트를 할 여유를 줘야 한다.

실행에 오래 걸리는 긴 작업을 분리

긴 작업(long task)이란 말 그대로 실행을 완료하는 데 오래 걸리는 작업을 의미한다.

  • 꼭 웹페이지에서 해야 하는 작업인가?
  • 긴 작업을 여러 개로 분리하기

자바스크립트 코드 최소화

크롬 개발자 도구에서 [도구 더보기]로 들어가서 [커버리지]를 클릭하고 기록버튼을 클릭하고 새로고침하면 커버리지가 기록된다.

이를 통해 웹페이지에서 사용되지 않은 코드가 얼마나 있는지 알 수 있다. 폴리필을 넣는 것 또한 매우 큰 용량을 차지하는데 SWC를 사용하고 있다면 SWC 내부에 구현되어 있기 때문에 별도의 처리는 필요 없다.

타사 자바스크립트 코드 실행의 지연

타사 스크립트는 대부분 웹페이지 로드에 중요한 자원이 아니므로

  • defer: 병렬 다운로드되면 페이지 완전 로딩 이후 맨 마지막에 실행
  • async: 병렬 다운로드되면 바로 실행
  • 없는 경우: script를 만나는 순간 다운로드 우선 후 코드 실행

따라서 타사 자바스크립트에서 최고는 defer, 그 다음 async로 지연시키는 것이 좋다.

누적 레이아웃 이동(CLS)

정의

페이지의 생명주기 동안 발생하는 모든 예기치 않은 이동에 대한 지표를 계산하는 것.

의미

CLS는 사용자의 가시적인 콘텐츠의 영향을 미쳐야 하기 때문에 뷰포트 내부의 요소에 대해서만 측정하며, 뷰포트 밖의 요소에 대해서는 측정하지 않는다. 최초 렌더링이 시작된 위치에서 레이아웃 이동이 발생하면 누적 레이아웃 이동 점수로 기록하게 된다. 위치에 영향을 미치지 않았다면 레이아웃 이동으로 간주되지 않는다.

사용자의 액션으로 인해 발생한 레이아웃 이동은 점수에 포함되지 않는다. 점수를 계산할 때 포함되는 내용은 다음과 같다.

  • 영향분율: 레이아웃 이동이 발생한 요소의 전체높이와 뷰포트 높이의 비율.
  • 거리분율: 레이아웃 이동이 발생한 요소가 뷰포트 대비 얼마나 이동했는지를 의미.

기본 점수

  • 0.1 이하: 좋음
  • 0.25이하 보통
  • 그 외: 나쁨

개선 방안

삽입이 예상되는 요소를 위한 추가적인 공간 확보

  • useEffect의 내부에서 요소에 영향을 미치는 작업, 뷰포트 내부에서 노출될 확률이 높은 작업을 최소하는 것이 좋다.
  • useEffect 사용이 불가피하다면 useLayoutEffect 훅을 사용해보는 것 또한 좋다.
  • 스켈레톤 UI로 미리 무언가가 동적으로 뜰 것으로 예상되는 공간을 미리 확보해 두기.
  • 가장 좋은 방법은 SSR.

폰트 로딩 최적화

폰트로 발생할 수 있는 문제는 두 가지

  • FOUT(flash of unstyled text): HTML 문서에서 폰트가 보이지 않고 대체 기본 폰트로 보이고 있다가 뒤늦게 폰트가 적용되는 현상
  • FOIT (flash of invisible text): HTML 문서에서 지정한 폰트가 보이지 않고, 기본 폰트도 없어서 텍스트가 없는 채로 있다가 뒤늦게 폰트가 로딩되면서 페이지에 렌더링되는 현상

사용자 기기의 기본 폰트 이외에 다른 폰트로 웹페이지를 보여주고 싶다면 다음과 같은 점을 유념해야 한다.

  • 의 preload 사용: 요소의 rel=preload는 페이지에서 즉시 필요로 하는 리소스를 명시하는 기능.
  • font-family: optional”: 폰트를 불러올 수 있는 방법은 5가지로 나뉜다.

최대한 중요한 폰트의 다운로드를 우선순위에 밀어넣고, 이 우선순위를 활용했음에도 빠르게 로딩하는데 실패했다면 다음을 기약하고 기본 폰트를 노출하는 것이다.

적절한 이미지 크기 설정

반응형 웹사이트란 사용자 기기의 크기에 따라 자연스럽게 콘텐츠를 자연스럽게 노출할 수 있도록 다양한 요소를 콘텐츠의 기기에 의존하도록 만든 웹사이트를 일컫는다.

img {
	width: 100%;
	height: auto;
}

이 경우 누적 레이아웃 이동이 커지는 결과를 낳는다. 앞서 설정한 CSS 때문에 높이를 이미지가 완전히 다운로드되기 전까지는 알 수 없기 때문에 이미지의 높이를 높게 잡아뒀다가 이미지가 완전히 로딩 완료된 이후에 기기의 너비만큼 계산해서 마침내 이미지 크기만큼 자리 잡을 수 있게 된 것이다.

height:auto 기법은 반응형 웹사이트에서 최적화할 수 있는 기법으로 기기의 너비가 어떻게 되는 원본 이미지의 가로세로 비율이 일정해 사용자에게 최적의 이미지를 보여줄 수 있는 장점이 있다. 그러나 앞선 사례처럼 이미지의 높이를 명확하게 알지 못하기 때문에 레이아웃 이동이 크게 발생한다는 단점이 있다.

  • width, height 지정: width와 height를 지정하는 것이 가장 좋은 방법이다. width:100%; height:auto 와 함께 원하는 비율로 지정하면 브라우저가 이미지를 로딩하기 전에 적절한 가로세로 비율을 계산해 이미지가 표시되는 만큼 면적을 할당해 둔다. 이는 aspect-ratio 속성 덕분인데, 이 속성은 이 속성은 브라우저의 유저 에이전트 스타일시트(브라우저가 기본으로 제공하는 스타일)에 포함돼 있으며, 이미지의 가로세로 비율을 자동으로 맞춰주는 역할을 한다.
  • 사용자 뷰포트 너비에 맞춰 다른 이미지를 제공하는 경우 반응형 이미지를 사용하고 싶다면 srcset 속성을 사용하는 것이 좋다.

핵심 웹 지표는 아니지만 성능 확인에 중요한 지표들

최초 바이트까지의 시간(Time To First Byte, TTFB)

: TTFB는 브라우저가 웹페이지의 첫 번째 바이트를 수신하는데 걸리는 시간을 의미.

  • 이 지표는 600ms 이상 걸릴 경우 개선이 필요한 것으로 간주된다.
  • 서버사이드 렌더링을 하는 애플리케이션의 경우 주의 깊게 봐야 한다.
  • 웹 페이지의 주된 방문객의 국적을 파악해 최대한 해당 국적과 가깝게 서버를 위치시키기
  • 리액트 SSR이라면 스트리밍 API를 사용하기

최초 콘텐츠풀 페인트(First Contentful Paint, FCP)

: FCP는 페이지가 로드되기 시작한 시점부터 페이지 콘텐츠의 일부가 화면에 렌더링될 때까지의 시간을 측정

  • 1.8초 이내 좋음, 3.0초 이내 보통, 그 이후 개선 필요

개선 사항

  • TTFB 개선
  • 렌더링을 가로막는 리소스 최소화: JS나 CSS 같은 렌더링을 가로막는 리소스 최소화, 렌더링 방해하는 리소스는 비동기적으로 로드하기.
  • Above the Fold에 대한 최적화: 최초 스크롤을 하지 않아도 보이는 영역에 게으른 로딩이나 스크립트에 의존하는 것은 모두 FCP에 대한 도움이 되지 않는다.
  • 페이지 리다이렉트 최소화
  • DOM 크기 최소화: DOM이 복잡하고 크다면 렌더링 시간이 오래 걸린다.

0개의 댓글