<ph type="x-smartling-placeholder">
지금까지 웹 개발자는 웹페이지의 주요 콘텐츠가 얼마나 빨리 로드되고 사용자에게 표시되는지 측정하는 데 어려움을 겪었습니다. load 또는 DOMContentLoaded와 같은 이전 측정항목은 사용자에게 표시되는 화면과 일치하지 않을 수 있으므로 제대로 작동하지 않습니다. 콘텐츠가 포함된 첫 페인트 (FCP)와 같은 새로운 사용자 중심 성능 측정항목은 로드 환경의 맨 처음에만 포착합니다. 페이지에 스플래시 화면이 표시되거나 로드 표시기가 표시되는 경우 이 시점은 사용자와 크게 관련이 없습니다.
이전에는 초기 페인트 후의 로드 경험을 더 잘 포착할 수 있도록 첫 번째 의미 있는 페인트 (FMP) 및 속도 지수 (SI) (모두 Lighthouse에서 사용 가능)와 같은 성능 측정항목을 권장했지만, 이러한 측정항목은 복잡하고 설명하기 어렵고 종종 잘못된 경우가 있기 때문에 페이지의 주요 콘텐츠가 로드된 시점을 파악하지 못합니다.
W3C 웹 성능 실무 그룹(W3C Web Performance Working Group)의 토론 및 Google에서 진행한 연구에 따르면 페이지의 주요 콘텐츠가 로드되는 시점을 측정하는 더 정확한 방법은 가장 큰 요소가 렌더링되는 시점을 확인하는 것입니다.
LCP란 무엇인가요?
LCP는 사용자가 처음 페이지로 이동한 시점을 기준으로 표시 영역에 표시되는 가장 큰 이미지 또는 텍스트 블록의 렌더링 시간을 보고합니다.
<ph type="x-smartling-placeholder">좋은 LCP 점수란 무엇인가요?
만족스러운 사용자 환경을 제공하기 위해 사이트의 최대 콘텐츠 페인트가 2.5초 이하가 되도록 노력해야 합니다. 대부분의 사용자가 이 목표를 달성할 수 있도록 모바일과 데스크톱 기기별로 분류된 페이지 로드의 75번째 백분위수를 측정하는 것이 좋습니다.
<ph type="x-smartling-placeholder">어떤 요소가 고려되나요?
현재 최대 콘텐츠 페인트 API, 요소 유형 최대 콘텐츠 페인트는 다음과 같습니다.
<img>
요소 (GIF 또는 애니메이션 PNG와 같은 애니메이션 콘텐츠에 첫 번째 프레임 표시 시간 사용)<svg>
요소 내의<image>
요소<video>
요소 (포스터 이미지 로드 시간 또는 동영상의 첫 번째 프레임 표시 시간 중 더 빠른 시간 사용)- CSS 그라데이션과 달리
url()
함수를 사용하여 로드된 배경 이미지가 있는 요소 - 텍스트 노드 또는 기타 인라인 수준 텍스트 요소 하위 요소를 포함하는 블록 수준 요소
초기에 작업을 간단하게 하기 위해 요소를 제한된 세트로 제한한 것이라는 점에 유의하세요. 향후 더 많은 연구가 진행됨에 따라 추가 요소 (예: 전체 <svg>
지원)가 추가될 수 있습니다.
LCP 측정에서는 일부 요소만 고려할 뿐만 아니라 휴리스틱을 사용하여 사용자에게 '콘텐츠가 없는' 것으로 보일 수 있는 특정 요소를 제외합니다. Chromium 기반 브라우저의 경우 다음이 포함됩니다.
- 사용자에게 표시되지 않는 불투명도가 0인 요소
- 콘텐츠가 아니라 배경으로 간주될 수 있는 전체 표시 영역을 덮는 요소
- 페이지의 실제 콘텐츠를 반영하지 않을 가능성이 높은 자리표시자 이미지 또는 엔트로피가 낮은 기타 이미지
브라우저는 가장 큰 콘텐츠가 포함된 요소가 무엇인지에 대한 사용자의 기대에 부응하기 위해 이러한 휴리스틱을 계속해서 개선해 나갈 것입니다.
이러한 '콘텐츠가 담긴' 휴리스틱은 콘텐츠가 포함된 첫 페인트 (FCP)에서 사용되는 것과 다를 수 있습니다. FCP는 LCP 후보에 적합하지 않더라도 자리표시자 이미지 또는 전체 표시 영역 이미지와 같은 일부 요소를 고려할 수 있습니다. 두 가지 모두 '콘텐츠가 포함된' 이러한 측정항목의 목적은 다릅니다. FCP는 모든 콘텐츠가 화면에 페인팅되는 시점을 측정하며 LCP는 기본 콘텐츠를 페인트할 때 측정하므로 LCP는 보다 선택적으로 활용할 수 있습니다.
요소의 크기는 어떻게 결정되나요?
LCP에 대해 보고되는 요소의 크기는 일반적으로 표시 영역 내에서 사용자가 볼 수 있는 크기입니다. 요소가 표시 영역 밖으로 확장되거나, 요소가 잘리거나 보이지 않는 오버플로가 있는 경우, 해당 부분은 요소의 크기에 가산되지 않습니다.
내장 크기에서 크기가 조정된 이미지 요소의 경우 보고되는 크기는 표시되는 크기 또는 기본 크기 중 더 작은 크기입니다.
텍스트 요소의 경우 LCP는 모든 텍스트 노드를 포함할 수 있는 가장 작은 직사각형만 고려합니다.
모든 요소에 대해 LCP는 CSS를 사용하여 적용된 여백, 패딩, 테두리를 고려하지 않습니다.
<ph type="x-smartling-placeholder">LCP는 언제 보고되나요?
웹페이지는 단계적으로 로드되는 경우가 많으므로 페이지에서 가장 큰 요소가 변경될 수도 있습니다.
이러한 변경 가능성을 처리하기 위해 브라우저는 첫 번째 프레임을 페인팅하자마자 가장 큰 콘텐츠가 포함된 요소를 식별하는 largest-contentful-paint
유형의 PerformanceEntry
를 전달합니다. 하지만 후속 프레임을 렌더링한 후에는 콘텐츠가 포함된 가장 큰 요소가 변경될 때마다 또 다른 PerformanceEntry
를 전달합니다.
예를 들어 텍스트와 히어로 이미지가 있는 페이지에서 브라우저는 처음에 텍스트를 렌더링할 수도 있습니다. 이때 브라우저는 element
속성이 <p>
또는 <h1>
를 참조할 가능성이 높은 largest-contentful-paint
항목을 전달합니다. 나중에 히어로 이미지 로드가 완료되면 두 번째 largest-contentful-paint
항목이 전달되고 element
속성이 <img>
를 참조합니다.
요소는 렌더링되어 사용자에게 표시된 후에만 가장 큰 콘텐츠가 포함된 요소로 간주될 수 있습니다. 아직 로드되지 않은 이미지는 '렌더링된' 것으로 간주되지 않습니다. 둘 다 글꼴 차단 기간 동안 텍스트 노드에서 웹 글꼴을 사용하지 않습니다. 이러한 경우 작은 요소가 가장 큰 콘텐츠가 포함된 요소로 보고될 수 있지만 큰 요소가 렌더링을 완료하는 즉시 또 다른 PerformanceEntry
가 생성됩니다.
이미지와 글꼴이 늦게 로드되는 것 외에도, 새로운 콘텐츠를 사용할 수 있게 되면 페이지에서 DOM에 새 요소를 추가할 수도 있습니다. 이러한 새 요소 중 하나라도 이전에 가장 큰 콘텐츠가 포함된 요소보다 큰 경우 새 PerformanceEntry
도 보고됩니다.
가장 큰 콘텐츠가 표시 영역이나 DOM에서 삭제되는 경우, 더 큰 요소가 렌더링되지 않는 한 이 요소는 가장 큰 콘텐츠 요소가 됩니다.
<ph type="x-smartling-placeholder">사용자 상호작용으로 인해 사용자에게 표시되는 항목이 변경되는 경우가 많으므로(특히 스크롤의 경우) 사용자가 탭이나 스크롤 또는 키 누름을 통해 페이지와 상호작용하는 즉시 브라우저가 새 항목 보고를 중지합니다.
분석을 위해 가장 최근에 전달된 PerformanceEntry
만 분석 서비스에 보고해야 합니다.
로드 시간과 렌더링 시간 비교
보안상의 이유로 Timing-Allow-Origin
헤더가 없는 교차 출처 이미지의 경우 이미지의 렌더링 타임스탬프가 노출되지 않습니다. 대신 로드 시간만 노출됩니다 (다른 많은 웹 API를 통해 이미 노출되어 있기 때문).
이로 인해 웹 API에서 LCP를 FCP보다 먼저 보고하는 것이 불가능해 보이는 상황이 발생할 수 있습니다. 이는 보안 제한으로 인해 발생하지는 않지만 나타납니다.
가능하면 측정항목의 정확성을 높이기 위해 항상 Timing-Allow-Origin
헤더를 설정하는 것이 좋습니다.
요소 레이아웃 및 크기 변경은 어떻게 처리되나요?
새로운 성능 항목을 계산하고 전달하는 성능 오버헤드를 낮게 유지하기 위해 요소의 크기나 위치를 변경해도 새 LCP 후보가 생성되지 않습니다. 표시 영역 내 요소의 초기 크기와 위치만 고려됩니다.
즉, 처음에 화면 밖에서 렌더링되었다가 화면상으로 전환되는 이미지는 보고되지 않을 수 있습니다. 또한 표시 영역에서 렌더링되었다가 아래로 내려가는 요소는 시야에서 벗어나도 여전히 초기 표시 영역 크기를 보고합니다.
예
다음은 최대 콘텐츠 페인트가 일부 인기 웹사이트에서 발생하는 몇 가지 예입니다.
<ph type="x-smartling-placeholder">![cnn.com의 최대 콘텐츠 페인트 타임라인](https://web.dev/static/articles/lcp/image/largest-contentful-paint-fc43128e011aa.png?hl=ko)
![Techcrunch.com의 최대 콘텐츠 페인트 타임라인](https://web.dev/static/articles/lcp/image/largest-contentful-paint-3713e2f14970a.png?hl=ko)
위의 두 타임라인에서 콘텐츠가 로드되면 가장 큰 요소가 변경됩니다. 첫 번째 예에서는 새 콘텐츠가 DOM에 추가되어 가장 큰 요소를 변경합니다. 두 번째 예에서는 레이아웃이 변경되고 이전에는 가장 컸던 콘텐츠가 표시 영역에서 삭제됩니다.
늦게 로드되는 콘텐츠가 페이지에 이미 있는 콘텐츠보다 큰 경우가 많지만 반드시 그런 것은 아닙니다. 다음 두 예는 페이지가 완전히 로드되기 전에 발생하는 LCP를 보여줍니다.
<ph type="x-smartling-placeholder">![instagram.com의 최대 콘텐츠 페인트 타임라인](https://web.dev/static/articles/lcp/image/largest-contentful-paint-9bc403e812154.png?hl=ko)
![google.com의 최대 콘텐츠 페인트 타임라인](https://web.dev/static/articles/lcp/image/largest-contentful-paint-6c5554de0eac7.png?hl=ko)
첫 번째 예에서 Instagram 로고는 비교적 일찍 로드되어 다른 콘텐츠가 점진적으로 표시되더라도 가장 큰 요소로 유지됩니다. Google 검색 결과 페이지의 예에서 가장 큰 요소는 이미지나 로고의 로드가 완료되기 전에 표시되는 텍스트 단락입니다. 모든 개별 이미지는 이 단락보다 작기 때문에 로드 프로세스가 진행되는 동안 가장 큰 요소로 유지됩니다.
<ph type="x-smartling-placeholder">LCP 측정 방법
LCP는 실험실이나 현장에서 측정할 수 있으며 다음 도구에서 사용할 수 있습니다.
현장 도구
실습 도구
JavaScript에서 LCP 측정
JavaScript에서 LCP를 측정하려면 Largest Contentful Paint 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를 측정하지만 사전 렌더링된 페이지의 경우
activationStart
부터 LCP를 측정해야 합니다. 사용자가 경험하는 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 타이밍을 파악하고 실험실 데이터를 사용하여 드릴다운하고 최적화하는 프로세스를 안내합니다.
추가 리소스
- performance.now()에서 애니 설리반의 Chrome 성능 모니터링에서 얻은 교훈 (2019년)
변경 로그
가끔 측정항목을 측정하는 데 사용되는 API에서 버그가 발견되며, 측정항목 자체의 정의에서도 버그가 발견됩니다. 그 결과, 때때로 변경이 이루어져야 하며, 내부 보고서 및 대시보드에서 이러한 변경사항이 개선되거나 회귀로 나타날 수 있습니다.
이를 관리하는 데 도움이 되도록 이러한 측정항목의 구현 또는 정의에 대한 모든 변경사항이 이 변경 로그에 표시됩니다.
이러한 측정항목에 관한 의견이 있으면 web-vitals-feedback Google 그룹에 의견을 보내주세요.