노트

LCP 하위 구간

LCP Breakdown

프론트엔드#performance#browser · 연결된 개념 9개

쉽게 말하면

LCP 하위 구간은 기차 여행 시간을 역에 도착하기까지, 기차를 타기까지 기다린 시간, 달린 시간, 내려서 문을 나서기까지로 나눠 보는 거예요. 어디서 오래 걸렸는지 알아야 무엇을 고칠지 정할 수 있죠.

비유의 한계 기차를 오래 기다린 건 출발역을 늦게 알아서일 수도 있어요. Resource Load Delay도 다운로드가 느린 게 아니라, HTML을 받고도 이미지를 늦게 발견하거나 늦게 요청해서 생기는 시간이에요.

LCP(Largest Contentful Paint, Core Web Vitals)를 순서대로 이어지는 네 구간으로 나눈 것. 네 구간을 더하면 LCP가 된다. LCP 숫자 하나만으로는 무엇을 고칠지 알 수 없어서, web.dev는 이 분해로 원인을 찾으라고 권한다.

구간시작 → 끝
TTFB(Time to First Byte)페이지 로드 시작 → HTML 응답의 첫 바이트 수신
Resource Load DelayTTFB 끝 → LCP 리소스 로드 시작
Resource Load DurationLCP 리소스 로드 시작 → 로드 끝
Element Render DelayLCP 리소스 로드 끝 → LCP 요소가 화면에 다 그려짐

LCP 요소가 시스템 폰트로 그린 텍스트처럼 리소스를 받을 필요가 없으면, Resource Load Delay와 Resource Load Duration은 0이다.

예시로 읽기

LCP 이미지를 스크립트가 나중에 <img>로 넣는 페이지를 생각해 보자.

0ms      페이지 이동 시작
600ms    HTML 첫 바이트 도착             TTFB                   = 600ms
1500ms   hero.jpg 요청 시작             Resource Load Delay    = 900ms
1800ms   hero.jpg 다운로드 끝           Resource Load Duration = 300ms
2000ms   이미지가 화면에 그려짐          Element Render Delay   = 200ms
                                       LCP                    = 2000ms

다운로드 자체는 300ms뿐인데, HTML을 받고도 이미지를 요청하기까지 900ms를 흘려보냈다. 이미지를 압축하는 것보다 HTML에 <img src>를 직접 쓰는 편이 효과가 크다.

잘 최적화된 페이지의 비율

구간LCP에서 차지하는 비율
TTFB약 40%
Resource Load Delay10% 미만
Resource Load Duration약 40%
Element Render Delay10% 미만

두 "지연" 구간은 0에 가까울수록 좋다. web.dev는 이 비율을 가이드로만 보고 밀리초 목표로 바꾸지 말라고 한다. 위 예시는 지연 구간이 55%라서 먼저 지연을 줄여야 한다.

구간별 원인

  • TTFB: 프론트엔드에서는 첫 바이트가 오기 전까지 아무것도 할 수 없다. 광고·단축 링크를 거치며 리다이렉트가 여러 번 쌓이거나, 분석용 URL 파라미터 때문에 CDN(Content Delivery Network) 엣지 캐시를 놓치고 원 서버까지 가는 경우가 흔한 원인이다. 연결 준비 비용도 여기에 들어간다(RTT와 연결 준비 비용)
  • Resource Load Delay: 리소스를 늦게 발견하거나 낮은 우선순위로 요청한다. 스크립트가 <img>를 넣거나, 지연 로딩 라이브러리가 주소를 data-src에 숨기거나, CSS 배경 이미지라서 프리로드 스캐너가 못 찾는 경우다. LCP 이미지에 loading="lazy"를 걸면 안 된다(이미지 loading 속성). 브라우저가 중요하다고 판단하지 못하면 fetchpriority로 알린다. 다른 출처의 리소스는 그 출처에 새로 연결하는 시간까지 든다
  • Resource Load Duration: 파일 크기, 서버까지의 거리, 동시에 받는 다른 리소스와의 대역폭 경합(HOL 블로킹과 HTTP/2 멀티플렉싱). 이미지 크기·포맷을 줄이고 CDN을 쓴다
  • Element Render Delay: 리소스는 받았는데 그리지 못한다. <head>의 렌더링 차단 CSS나 동기 스크립트, LCP 리소스보다 늦게 끝나는 큰 스타일시트, 아직 DOM에 없는 요소(JS 대기), A/B 테스트 라이브러리가 숨긴 요소, 메인 스레드의 긴 태스크(이벤트 루프)가 원인이다 → 브라우저 렌더링 파이프라인

정리하면 Resource Load Delay는 "요청을 늦게 시작한 시간", Resource Load Duration은 "받는 데 걸린 시간", Element Render Delay는 "받고 나서 그리기까지 늦은 시간"이다. 이미지가 늦게 뜬다고 바로 이미지 압축부터 하지 않고, 어느 구간이 긴지 먼저 본다.

출처: web.dev — Optimize Largest Contentful Paint: LCP breakdown · web.dev — Optimize LCP: Optimal subpart times · web.dev — Optimize LCP: How to optimize each part

연결된 개념

이 노트를 가리키는 문서

뜻이 가까운 노트

  • 롱 태스크

    메인 스레드를 50ms 넘게 붙잡는 작업. W3C Long Tasks 명세는 이벤트 루프 태스크(뒤따르는 마이크로태스크 처리 포함), 렌더링 갱신 단계, 이벤트 루프 밖에서 브라우저가 UI 스레드로 하는 일 가운데 50ms를 넘는 것을 롱 태스크로 본다. 태스크는 도중에 끊기지 않으므로 그동안 클릭·키 입력 처리와 화면 갱신이 모두 밀린다(이벤트 루프).

  • Lighthouse 성능 점수 읽기

    Lighthouse 성능 점수는 다섯 지표의 가중 평균이다. 한 지표를 개선했는데 점수가 떨어지는 일이 생기는 이유와, 점수를 분포로 봐야 하는 이유.

  • loading 경계와 레이아웃 끌어올리기

    Next.js App Router에서 loading.tsx는 같은 세그먼트의 page와 그 아래(하위 layout 포함)를 suspense로 감싸지만, **같은 세그먼트의 layout은 감싸지 않는다**. 그래서 데이터를 기다릴 필요가 없는 공통 UI(탭바, 필터 헤더)를 page에서 layout으로 끌어올리면 스켈레톤에 덮이지 않고 처음부터 실제 모습으로 보인다.

  • content-visibility

    화면 밖에 있는 요소의 렌더링을 건너뛰어도 된다고 브라우저에 알려 주는 CSS 속성. auto를 주면 뷰포트에서 멀리 있는 요소의 레이아웃·페인트를 생략하므로, 긴 페이지의 첫 렌더링과 스크롤이 빨라진다.

  • preload·prefetch·preconnect

    link 태그의 rel로 브라우저에게 "이건 미리 받아 둬", "이 서버와는 미리 연결해 둬"라고 알려 주는 기법. 브라우저가 HTML을 끝까지 읽기 전에 중요한 일을 앞당겨 시작하게 한다.

보기 옵션