Largest Contentful Paint (LCP)

브라우저 지원

  • Chrome: 77 <ph type="x-smartling-placeholder">
  • Edge: 79 <ph type="x-smartling-placeholder">
  • Firefox: 122 <ph type="x-smartling-placeholder">
  • Safari: 지원되지 않음 <ph type="x-smartling-placeholder">

소스

지금까지 웹 개발자는 웹페이지의 주요 콘텐츠가 얼마나 빨리 로드되고 사용자에게 표시되는지 측정하는 데 어려움을 겪었습니다. load 또는 DOMContentLoaded와 같은 이전 측정항목은 사용자에게 표시되는 화면과 일치하지 않을 수 있으므로 제대로 작동하지 않습니다. 또한 최초 콘텐츠 페인트(FCP)와 같은 최신 사용자 중심 성능 측정항목은 로드 환경의 시작 부분만 포착합니다. 페이지에 스플래시 화면이 표시되거나 로드 표시기가 표시되는 순간은 사용자와 관련성이 높지 않습니다.

이전에는 초기 페인트 후 로드 경험을 더 잘 포착할 수 있도록 첫 번째 의미 있는 페인트 (FMP)속도 지수 (SI) (모두 Lighthouse에서 사용 가능)와 같은 성능 측정항목을 권장했지만, 이러한 측정항목은 복잡하고 설명하기 어렵고 잘못된 경우가 많아 페이지의 주요 콘텐츠가 로드된 시점을 파악하지 못합니다.

W3C 웹 성능 작업반의 논의와 Google에서 수행한 연구에 따르면 페이지의 기본 콘텐츠가 로드되는 시점을 측정하는 더 정확한 방법은 가장 큰 요소가 렌더링되는 시점을 확인하는 것입니다.

LCP란 무엇인가요?

LCP는 사용자가 처음 페이지로 이동했을 때를 기준으로 표시 영역에 표시되는 가장 큰 이미지, 텍스트 블록, 동영상의 렌더링 시간을 보고합니다.

좋은 LCP 점수는 얼마인가요?

만족스러운 사용자 환경을 제공하기 위해 사이트의 최대 콘텐츠 페인트가 2.5초 이하가 되도록 노력해야 합니다. 대부분의 사용자가 이 목표를 달성하도록 하려면 모바일 및 데스크톱 기기별로 분류된 페이지 로드의 75번째 백분위수를 측정하는 것이 좋습니다.

LCP 값이 2.5초 이하이면 좋고 4.0초를 초과하면 나쁘며 그 사이의 값이면 개선이 필요합니다.
LCP 값이 2.5초 이하이면 좋습니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.

어떤 요소가 고려되나요?

현재 최대 콘텐츠 렌더링 시간 API에 지정된 대로 최대 콘텐츠 렌더링 시간에 고려되는 요소 유형은 다음과 같습니다.

처음에는 간단하게 시작할 수 있도록 요소를 이 제한된 세트로 제한한 것은 의도적인 조치였습니다. 향후 더 많은 연구가 진행되면 추가 요소(예: 전체 <svg> 지원)가 추가될 수 있습니다.

LCP 측정은 일부 요소만 고려하는 것 외에도 사용자가 '콘텐츠가 없는' 것으로 간주할 가능성이 높은 특정 요소를 제외하기 위해 휴리스틱을 사용합니다. Chromium 기반 브라우저의 경우 다음이 포함됩니다.

  • 불투명도가 0이므로 사용자에게 표시되지 않는 요소
  • 콘텐츠가 아니라 배경으로 간주될 수 있는 전체 표시 영역을 덮는 요소
  • 페이지의 실제 콘텐츠를 반영하지 않을 가능성이 높은 자리표시자 이미지 또는 엔트로피가 낮은 기타 이미지

가장 큰 콘텐츠가 포함된 요소에 대한 사용자의 기대에 부합하기 위해 브라우저는 이러한 휴리스틱을 계속 개선할 것입니다.

이러한 '콘텐츠가 포함된' 휴리스틱은 콘텐츠가 포함된 첫 페인트(FCP)에서 사용하는 휴리스틱과 다를 수 있습니다. FCP에서는 자리표시자 이미지나 전체 표시 영역 이미지와 같이 LCP 후보가 될 자격이 없는 요소도 고려할 수 있습니다. 두 측정항목 모두 이름에 'contentful'을 사용하지만 목적은 다릅니다. FCP는 모든 콘텐츠가 화면에 페인트되는 시점을 측정하고 LCP는 기본 콘텐츠가 페인트되는 시점을 측정하므로 LCP는 더 선택적으로 작동합니다.

요소의 크기는 어떻게 결정되나요?

LCP에 대해 보고되는 요소의 크기는 일반적으로 표시 영역 내에서 사용자가 볼 수 있는 크기입니다. 요소가 표시 영역 밖으로 확장되거나, 요소가 잘리거나 보이지 않는 오버플로가 있는 경우, 해당 부분은 요소의 크기에 가산되지 않습니다.

기본 크기에서 크기가 조정된 이미지 요소의 경우 표시되는 크기와 기본 크기 중 더 작은 값이 보고됩니다.

텍스트 요소의 경우 LCP는 모든 텍스트 노드를 포함할 수 있는 가장 작은 직사각형만 고려합니다.

모든 요소의 경우 LCP는 CSS를 사용하여 적용된 여백, 패딩 또는 테두리를 고려하지 않습니다.

LCP는 언제 보고되나요?

웹페이지는 단계적으로 로드되는 경우가 많으므로 페이지에서 가장 큰 요소가 변경될 수도 있습니다.

이러한 잠재적 변경사항을 처리하기 위해 브라우저는 첫 번째 프레임을 페인트하는 즉시 가장 큰 콘텐츠 요소를 식별하는 largest-contentful-paint 유형의 PerformanceEntry를 전달합니다. 하지만 후속 프레임을 렌더링한 후에는 콘텐츠가 포함된 가장 큰 요소가 변경될 때마다 또 다른 PerformanceEntry를 전달합니다.

예를 들어 텍스트와 히어로 이미지가 있는 페이지에서 브라우저는 처음에 텍스트를 렌더링할 수도 있습니다. 이때 브라우저는 element 속성이 <p> 또는 <h1>를 참조할 가능성이 높은 largest-contentful-paint 항목을 전달합니다. 나중에 히어로 이미지 로드가 완료되면 두 번째 largest-contentful-paint 항목이 전달되고 element 속성이 <img>를 참조합니다.

요소는 렌더링되어 사용자에게 표시된 후에만 가장 큰 콘텐츠가 포함된 요소로 간주될 수 있습니다. 아직 로드되지 않은 이미지는 '렌더링된' 것으로 간주되지 않습니다. 글꼴 차단 기간 동안 웹 글꼴을 사용하는 텍스트 노드도 마찬가지입니다. 이 경우 더 작은 요소가 콘텐츠가 포함된 가장 큰 요소로 보고될 수 있지만 더 큰 요소의 렌더링이 완료되는 즉시 다른 PerformanceEntry가 생성됩니다.

지연된 이미지와 글꼴 외에도 페이지는 새 콘텐츠가 제공될 때 DOM에 새 요소를 추가할 수 있습니다. 이러한 새 요소 중 이전의 가장 큰 콘텐츠 요소보다 큰 요소가 있으면 새 PerformanceEntry도 보고됩니다.

가장 큰 콘텐츠가 표시 영역이나 DOM에서 삭제되는 경우, 더 큰 요소가 렌더링되지 않는 한 이 요소는 가장 큰 콘텐츠 요소가 됩니다.

사용자 상호작용으로 인해 사용자에게 표시되는 항목이 변경되는 경우가 많으므로(특히 스크롤의 경우) 사용자가 탭이나 스크롤 또는 키 누름을 통해 페이지와 상호작용하는 즉시 브라우저가 새 항목 보고를 중지합니다.

분석을 위해 가장 최근에 전달된 PerformanceEntry만 분석 서비스에 보고해야 합니다.

로드 시간과 렌더링 시간 비교

보안상의 이유로 이미지의 렌더링 타임스탬프는 Timing-Allow-Origin 헤더가 없는 교차 출처 이미지에 노출되지 않습니다. 대신 로드 시간만 노출됩니다(이미 다른 많은 웹 API를 통해 노출되기 때문).

이로 인해 웹 API에서 LCP가 FCP보다 먼저 보고되는 것처럼 보이는 불가능한 상황이 발생할 수 있습니다. 이러한 상황은 보안 제한으로 인해 발생할 수 있지만, 그렇지 않은 것으로 보입니다.

가능하면 항상 Timing-Allow-Origin 헤더를 설정하여 측정항목의 정확성을 높이는 것이 좋습니다.

요소 레이아웃 및 크기 변경은 어떻게 처리되나요?

새 실적 항목을 계산하고 전달하는 데 드는 성능 오버헤드를 낮게 유지하기 위해 요소의 크기나 위치가 변경되더라도 새 LCP 후보가 생성되지 않습니다. 표시 영역에서 요소의 초기 크기와 위치만 고려됩니다.

즉, 처음에는 화면 밖에서 렌더링되었다가 화면 안으로 전환되는 이미지는 보고되지 않을 수 있습니다. 또한 처음에 표시 영역에서 렌더링된 요소가 아래로 내려가도 시야에서 벗어나면 여전히 초기 표시 영역 내 크기가 보고됩니다.

다음은 최대 콘텐츠 페인트가 일부 인기 웹사이트에서 발생하는 몇 가지 예입니다.

cnn.com의 최대 콘텐츠 페인트 타임라인
cnn.com의 LCP 타임라인입니다.
techcrunch.com의 최대 콘텐츠 페인트 타임라인
techcrunch.com의 LCP 타임라인입니다.

위의 두 타임라인에서 콘텐츠가 로드되면 가장 큰 요소가 변경됩니다. 첫 번째 예에서는 DOM에 새 콘텐츠가 추가되어 가장 큰 요소를 변경합니다. 두 번째 예에서는 레이아웃이 변경되고 이전에 가장 컸던 콘텐츠가 표시 영역에서 삭제됩니다.

늦게 로드되는 콘텐츠가 페이지에 이미 있는 콘텐츠보다 큰 경우가 많지만 반드시 그런 것은 아닙니다. 다음 두 예는 페이지가 완전히 로드되기 전에 발생하는 LCP를 보여줍니다.

instagram.com의 최대 콘텐츠 페인트 타임라인
instagram.com의 LCP 타임라인입니다.
google.com의 최대 콘텐츠 페인트 타임라인
google.com의 LCP 타임라인입니다.

첫 번째 예에서 Instagram 로고는 비교적 일찍 로드되어 다른 콘텐츠가 점진적으로 표시되더라도 가장 큰 요소로 유지됩니다. Google 검색 결과 페이지 예시에서 가장 큰 요소는 이미지나 로고가 로드되기 전에 표시되는 텍스트 단락입니다. 모든 개별 이미지가 이 단락보다 작으므로 로드 프로세스 전반에서 가장 큰 요소로 남아 있습니다.

LCP 측정 방법

LCP는 실험실이나 현장에서 측정할 수 있으며 다음 도구에서 사용할 수 있습니다.

현장 도구

실습 도구

JavaScript에서 LCP 측정

JavaScript에서 LCP를 측정하려면 최대 콘텐츠 페인트 API를 사용하면 됩니다. 다음 예에서는 largest-contentful-paint 항목을 수신 대기하고 콘솔에 로깅하는 PerformanceObserver를 만드는 방법을 보여줍니다.

new PerformanceObserver((entryList) => {
  for (const entry of entryList.getEntries()) {
    console.log('LCP candidate:', entry.startTime, entry);
  }
}).observe({type: 'largest-contentful-paint', buffered: true});

위 예에서 로깅된 각 largest-contentful-paint 항목은 현재 LCP 후보를 나타냅니다. 일반적으로 내보낸 마지막 항목의 startTime 값이 LCP 값이지만 항상 그런 것은 아닙니다. 일부 largest-contentful-paint 항목이 LCP 측정에 유효하지 않습니다.

다음 섹션에는 API에서 보고하는 내용과 측정항목 계산 방법의 차이점이 나와 있습니다.

측정항목과 API의 차이점

  • API는 백그라운드 탭에 로드된 페이지의 largest-contentful-paint 항목을 전달하지만 LCP를 계산할 때 이러한 페이지는 무시해야 합니다.
  • API는 페이지가 백그라운드로 전환된 후에도 largest-contentful-paint 항목을 계속 전달하지만 LCP를 계산할 때는 이러한 항목을 무시해야 합니다 (페이지가 전체 포그라운드에 있는 경우에만 요소를 고려할 수 있음).
  • 페이지가 뒤로-앞으로 캐시에서 복원될 때 API는 largest-contentful-paint 항목을 보고하지 않지만 이러한 경우 사용자가 LCP를 별도의 페이지 방문으로 경험하므로 LCP를 측정해야 합니다.
  • API는 iframe 내의 요소를 고려하지 않지만 측정항목은 페이지의 사용자 환경의 일부이므로 고려합니다. iframe 내에 LCP가 있는 페이지(예: 삽입된 동영상의 포스터 이미지)에서는 CrUX와 RUM 간에 차이가 표시됩니다. LCP를 올바르게 측정하려면 이러한 요소를 고려해야 합니다. 하위 프레임은 API를 사용하여 집계를 위해 largest-contentful-paint 항목을 상위 프레임에 보고할 수 있습니다.
  • API는 탐색 시작부터 LCP를 측정하지만 사전 렌더링된 페이지의 경우 사용자가 경험한 LCP 시간에 해당하므로 activationStart부터 LCP를 측정해야 합니다.

개발자는 이러한 미묘한 차이점을 모두 기억하는 대신 web-vitals JavaScript 라이브러리를 사용하여 LCP를 측정할 수 있습니다. 이 라이브러리는 이러한 차이점을 자동으로 처리합니다(가능한 경우, iframe 문제는 다루지 않음).

import {onLCP} from 'web-vitals';

// Measure and log LCP as soon as it's available.
onLCP(console.log);

JavaScript에서 LCP를 측정하는 방법에 관한 전체 예는 onLCP()의 소스 코드를 참고하세요.

가장 큰 요소가 가장 중요하지 않다면 어떻게 해야 할까요?

경우에 따라 페이지에서 가장 중요한 요소가 가장 큰 요소와 동일하지 않을 수 있으며, 개발자는 이러한 다른 요소의 렌더링 시간을 측정하는 데 더 관심이 있을 수 있습니다. 커스텀 측정항목 도움말에 설명된 대로 Element Timing API를 사용하면 됩니다.

LCP를 개선하는 방법

LCP 최적화에 관한 전체 가이드에서는 현장에서 LCP 타이밍을 파악하고 실험실 데이터를 사용하여 드릴다운하고 최적화하는 프로세스를 안내합니다.

추가 리소스

변경 로그

측정항목이 측정항목을 측정하는 데 사용되는 API에서 발견되는 경우가 있으며, 측정항목 자체의 정의에서도 버그가 발견되는 경우가 있습니다. 그 결과, 때때로 변경이 이루어져야 하며, 이러한 변경사항은 내부 보고서 및 대시보드에서 개선되거나 회귀로 나타날 수 있습니다.

이를 관리하는 데 도움이 되도록 이러한 측정항목의 구현 또는 정의에 대한 모든 변경사항은 이 변경 로그에 표시됩니다.

이러한 측정항목에 관한 의견이 있으면 web-vitals-feedback Google 그룹에 의견을 보내주세요.