정의
페이지에서 가장 큰 콘텐츠(보통 히어로 제목이나 큰 이미지)가 화면에 그려지는 시각을 LCP(Largest Contentful Paint)라고 한다. 이 LCP가 느린데 이미지 바이트가 작고 메인 스레드도 한가하면(TBT≈0), 병목은 "다운로드"가 아니라 그 LCP 요소가 클라이언트 컴포넌트 경계 안에 있어 JavaScript hydration이 끝나야 비로소 그려지는 것이다. Lighthouse는 이를 LCP breakdown의 "element render delay"(요소가 준비된 뒤 실제로 그려지기까지의 지연)로 보여 준다.
용어를 풀면, hydration은 서버가 만든 정적 HTML에 React가 나중에 이벤트를 붙여 살아 움직이게 하는 과정이고, TBT(Total Blocking Time) 는 메인 스레드가 긴 작업에 막혀 입력에 반응 못 한 총 시간이다.
왜 필요한가
증상: LCP가 5초대로 느리다. 직관적으로 "히어로 이미지를 줄이자"가 떠오른다. 그런데 이미지를 아무리 압축해도 점수가 안 오른다. LCP 요소가 "use client" 컴포넌트 + 애니메이션 라이브러리 안에 있으면, 서버 HTML은 비어 있거나 미완성이고 브라우저가 그 청크를 받아 hydration을 끝낸 뒤에야 최종 픽셀이 뜬다. 즉 페인트가 자바스크립트 실행에 인질로 잡힌다. 이때 공략 대상은 에셋이 아니라 "그 경계에서 클라이언트 JS를 빼는 것"이다. 진단을 틀리면 며칠을 이미지 최적화에 낭비하고도 점수가 그대로다.
동작 원리
Lighthouse는 LCP를 네 구간으로 쪼갠다.
| 구간 | 의미 | 이게 크면 |
|---|---|---|
| TTFB | 서버 첫 바이트까지 | 서버/네트워크 |
| load delay | LCP 리소스 발견이 늦음 | 늦은 preload/발견 |
| load time | LCP 리소스 다운로드 시간 | 큰 이미지 |
| render delay | 리소스는 준비됐는데 그려지기까지의 지연 | hydration/렌더 차단 |
이미지가 작고 TTFB 정상인데 render delay가 크면, LCP 요소가 클라이언트 경계 안이라 그 청크의 다운로드+실행이 페인트 앞을 막고 있다는 신호다. 서버 컴포넌트로 렌더하면 최종 마크업이 첫 HTML에 이미 들어 있어 hydration을 기다릴 필요가 없다.
실무 적용
-
breakdown 확인 — Lighthouse의 LCP insight에서 render delay 값을 본다. 크면 hydration 의심.
-
LCP 서피스를 서버화 — 히어로·상단 스토리 섹션을 서버 컴포넌트로 바꾸고, 움직임이 필요하면 애니메이션 라이브러리 대신 CSS(스크롤 구동 애니메이션 등)로 대체한다.
-
무거운 프로바이더 격리 — auth/query/motion/서비스워커 등 무거운 컨텍스트 프로바이더를 최상위가 아니라 앱 서피스 전용 레이아웃으로 내려, 정적 랜딩 청크에서 완전히 빠지게 한다.
-
상태가 꼭 필요하면 최소화 — 트리거 한 번짜리 등장 효과는 IntersectionObserver 한 조각까지만 클라이언트로 둔다.
트레이드오프
- 서버화 + CSS 전환은 diff가 크지만 랜딩 청크에서 라이브러리를 통째로 제거해 효과가 확실하다. 반대로 라이브러리의
LazyMotion같은 부분 최적화는 diff는 작아도 그 라이브러리가 여전히 청크에 남는다. - 측정 함정: Lighthouse 시뮬레이션(Lantern, CPU 4배 느리게 가정)은 하한을 만들어 실제 관측 LCP와 크게 다를 수 있다. 어느 지점부턴 코드가 아니라 시뮬 하한이라 더 줄지 않는다 — 이때는 멈추는 게 맞다.
사용하면 안 되는 경우
- LCP 요소가 진짜로 큰 이미지라 load time이 지배적이면, 여기 처방(서버화) 대신 이미지 최적화가 답이다. 먼저 breakdown으로 어느 구간인지 확정한다.
- 강한 상호작용이 상단에 반드시 필요한 앱 화면(대시보드 등)에서 무리하게 클라이언트 JS를 빼면 기능이 깨진다 — 랜딩/마케팅 표면에 집중한다.
흔한 실수
- LCP 느림 = 이미지 문제로 단정하고 render delay를 안 본다.
- 큰 원본 이미지를 작게 표시하는 브랜드 마크를 그대로 둠 — 프레임워크가 초기 HTML의
<img>를 자동 preload해 크리티컬 패스에 큰 바이트를 얹는다(전용 소형 에셋 필요). - 시뮬 하한에 도달했는데 계속 최적화에 시간을 쓴다(과투자).
관련 개념
- largest-contentful-paint — LCP 지표 자체와 일반 최적화
- critical-rendering-path — HTML→렌더 경로와 차단 요소
- scroll-driven-narrative-layout — 모션을 CSS로 대체하는 서버 친화 레이아웃
- lighthouse-measurement-accuracy — 시뮬 하한과 observed의 차이
- readonly-viewer-bundle-splitting — 표면별로 무거운 의존성 제거