Ray Book
프론트엔드 성능 최적화

성능을 측정하라, Core Web Vitals

LCP, INP, CLS, 사용자 경험을 숫자로 측정하는 세 가지 핵심 지표를 시각화합니다

performancecore-web-vitalslcpinpclslighthouse

핵심 질문

"이 페이지가 빠른가, 느린가"를 어떻게 숫자로 증명할 수 있는가?

"체감상 빠르다"는 근거가 될 수 없습니다. 성능 개선의 첫 단계는 측정입니다. Google은 사용자 경험을 대표하는 세 가지 핵심 지표인 LCP, INP, CLS를 Core Web Vitals로 정의하고, 이를 검색 순위에 반영합니다.

왜 측정해야 하는가

성능은 비즈니스에 직접적인 영향을 미칩니다.

  • 로딩이 1초 느려지면 전환율이 7% 떨어진다는 연구 결과가 있습니다
  • Google은 Core Web Vitals를 페이지 경험 신호에 포함하여 검색 순위에 반영합니다
  • 느린 페이지는 사용자 이탈률을 높이고, SEO 점수를 낮춥니다

측정 없이는 개선이 불가능합니다. "어디가 느린지" 모르면 "무엇을 고쳐야 하는지"도 알 수 없습니다.

LCP, Largest Contentful Paint

LCP는 뷰포트에서 가장 큰 콘텐츠 요소가 렌더링 완료된 시점을 측정합니다. "사용자가 주요 콘텐츠를 볼 수 있게 된 순간"을 나타내는 로딩 지표입니다.

LCP 후보가 되는 요소:

  • <img> 요소
  • <video> 요소의 포스터 이미지
  • CSS background-image로 로드한 이미지
  • 텍스트 노드를 포함하는 블록 레벨 요소
등급임곗값
Good2.5초 이하
Needs Improvement2.5초 ~ 4.0초
Poor4.0초 초과

LCP를 개선하는 핵심 전략:

  1. 서버 응답 시간 줄이기, TTFB (Time to First Byte) 가 느리면 모든 지표가 밀립니다
  2. 렌더 차단 리소스 제거, 불필요한 동기 CSS/JS를 제거하거나 defer/async 처리
  3. LCP 리소스를 preload, <link rel="preload">로 브라우저가 일찍 발견하게 합니다
  4. 이미지 최적화, WebP/AVIF 포맷, 적절한 크기, CDN 배포

INP, Interaction to Next Paint

INP는 사용자의 인터랙션 (클릭, 탭, 키 입력) 에 대해 브라우저가 다음 프레임을 그리기까지의 지연 시간을 측정합니다. 2024년 3월, 기존의 FID (First Input Delay) 를 대체했습니다.

FID는 첫 번째 인터랙션의 입력 지연만 측정했습니다. INP는 페이지 전체 수명 동안 발생하는 모든 인터랙션을 추적하고, 그중 가장 느린 값 (또는 상위 백분위) 을 대표값으로 사용합니다.

등급임곗값
Good200ms 이하
Needs Improvement200ms ~ 500ms
Poor500ms 초과

INP를 구성하는 세 구간:

  1. Input delay, 이벤트 핸들러가 실행되기까지의 대기 시간 (메인 스레드가 바쁜 경우)
  2. Processing time, 이벤트 핸들러의 실행 시간
  3. Presentation delay, 렌더링이 완료되어 다음 프레임이 그려지기까지의 시간

INP를 개선하는 핵심 전략:

  1. 긴 작업 쪼개기, 50ms 이상의 Long Task를 scheduler.yield() 또는 setTimeout으로 분할
  2. 불필요한 리렌더링 방지, React의 useMemo, useCallback, memo
  3. 메인 스레드 부하 줄이기, 무거운 연산은 Web Worker로 이동

CLS, Cumulative Layout Shift

CLS는 페이지 로드 중 예기치 않은 레이아웃 이동의 누적 점수를 측정합니다. 버튼을 누르려는데 갑자기 광고가 끼어들어 엉뚱한 곳을 클릭했던 경험, 바로 이런 게 CLS가 잡아내는 문제입니다.

등급임곗값
Good0.1 이하
Needs Improvement0.1 ~ 0.25
Poor0.25 초과

CLS 점수 계산: 영향 비율 (impact fraction) x 거리 비율 (distance fraction). 뷰포트의 50%를 차지하는 요소가 뷰포트 높이의 25%만큼 이동하면, CLS = 0.5 x 0.25 = 0.125입니다.

CLS를 개선하는 핵심 전략:

  1. 이미지/비디오에 크기 지정, width, height 속성 또는 aspect-ratio CSS
  2. 동적 콘텐츠 공간 확보, 광고, 배너, 폰트 로드 영역에 미리 공간을 예약
  3. 웹 폰트 FOUT 방지, font-display: swap<link rel="preload">를 함께 사용
  4. transform 애니메이션 사용, top/left 대신 transform은 레이아웃 시프트를 유발하지 않습니다

시각화, 페이지 로드 타임라인

아래 시각화는 페이지가 로드되는 과정에서 각 Core Web Vitals 지표가 어느 시점에 측정되는지 보여줍니다.

NavigationNavigation Start1 / 5
Navigation
FCP
LCP
INP
CLS
blank

사용자가 URL을 입력하거나 링크를 클릭한 순간 — 모든 측정의 기준점입니다. 아직 화면에는 아무것도 보이지 않습니다.

측정 도구

Lighthouse

Chrome DevTools에 내장된 성능 감사 도구입니다. Lab 데이터 (제어된 환경) 를 제공합니다.

# CLI로 실행
npx lighthouse https://example.com --output html --output-path report.html

Lab 데이터는 네트워크 속도, 디바이스 성능을 시뮬레이션하므로 실제 사용자 환경과 다를 수 있습니다. 개발 중 빠른 피드백에 유용합니다.

Chrome DevTools Performance 패널

실제 페이지 로드를 녹화하여 메인 스레드 활동, 레이아웃 시프트, Long Task 등을 타임라인으로 분석합니다. INP 디버깅에 특히 유용합니다.

web-vitals 라이브러리

실제 사용자 환경 (Field 데이터) 에서 Core Web Vitals를 측정합니다.

import { onLCP, onINP, onCLS } from "web-vitals";

onLCP(console.log);   // Largest Contentful Paint
onINP(console.log);   // Interaction to Next Paint
onCLS(console.log);   // Cumulative Layout Shift

측정된 데이터를 분석 서비스 (Google Analytics, 자체 엔드포인트) 로 전송하면 실제 사용자의 75번째 백분위 수 (p75) 를 기준으로 성능을 평가할 수 있습니다.

Chrome UX Report (CrUX)

Google이 수집하는 실제 사용자 데이터입니다. PageSpeed Insights와 Search Console에서 확인할 수 있습니다. 28일간의 p75 데이터를 기준으로 하므로, 배포 후 효과를 확인하려면 시간이 필요합니다.

체크리스트

  • LCP 2.5초 이하, INP 200ms 이하, CLS 0.1 이하를 목표로 설정했는가
  • web-vitals 라이브러리로 Field 데이터를 수집하고 있는가
  • Lighthouse CI를 배포 파이프라인에 통합했는가
  • LCP 요소를 식별하고 preload를 적용했는가
  • 이미지에 width/height 또는 aspect-ratio를 지정했는가
  • Long Task를 50ms 이하로 분할했는가

다음 글에서는

성능을 측정하는 방법을 알았으니, 다음 글에서는 가장 직접적인 병목, 번들 크기를 다룹니다. 코드 스플리팅, 트리 쉐이킹, 압축으로 네트워크 전송량을 줄이는 전략을 시각화합니다.