1. 소개
이 섹션은 규범적이지 않습니다. LargestContentfulPaint API는 개발자가 웹 페이지의 로딩 및 렌더링 과정을 파악하여 최적화할 수 있도록 합니다.
개발자는 사용자의 시각적 렌더링 경험과 상관관계가 높은 신뢰할 수 있는 지표가 필요합니다. Paint 로딩 지표인 First Paint와 First Contentful Paint는 초기 렌더링에 중점을 두지만, 페인팅된 콘텐츠의 중요성을 고려하지 않아 사용자가 페이지를 유용하다고 여기지 않는 시점까지의 시간도 표시할 수 있습니다.
Largest Contentful Paint(LCP)는 다음과 같은 페이지 로드 지표가 되는 것을 목표로 합니다:
-
First Paint와 First Contentful Paint보다 사용자 경험과 더 잘 상관관계가 있음
-
이해 및 추론이 용이함
-
게임화(지표 조작)의 가능성을 줄임
페이지 로딩 과정 중의 가장 큰 페인트는 사용자 관점에서 의미 있는 이벤트를 나타낼 가능성이 높으므로 기본적으로 개발자에게 노출하여, 성능 팀, 분석 제공자, 실험실 기반 측정 도구가 콘텐츠 생성자의 별도 주석 작업 없이 해당 지표를 수집할 수 있도록 하는 것이 목표입니다.
이 API는 [PAINT-TIMING]에서 정의된 개념에 크게 의존합니다. 이 개념들은 고수준 기능의 기반이 되는 저수준 프리미티브로 볼 수 있습니다. 콘텐츠 제작자가 페이지의 중요한 시점에 주석을 달고 싶을 때 사용할 수 있는 API는 [ELEMENT-TIMING]으로, 보고되는 요소에 대해 더 많은 제어를 제공합니다.
참고: Largest Contentful Paint API는 타이밍 적격 요소만을 노출합니다. Element Timing과 달리 LCP 측정을 위해 요소에 주석을 달 필요가 없습니다.
1.1. 가장 큰 콘텐츠
이 API에 사용되는 알고리즘은 지금까지 확인된 콘텐츠를 추적합니다. 새로운 더 큰 콘텐츠가 발견되면 새로운 엔트리가 생성됩니다. 제거된 콘텐츠도 알고리즘에서 고려되며, 특히 제거된 콘텐츠가 가장 컸던 경우 더 큰 콘텐츠가 추가될 때만 새 엔트리가 생성됩니다. 사용자의 스크롤이나 입력 이벤트가 발생하면 새로운 콘텐츠가 추가될 가능성이 높으므로, 이때 알고리즘은 종료됩니다.
1.2. 사용 예시
다음 예시는 이미지와 큰 본문 텍스트를 보여줍니다. 개발자는 페이지가 로딩 중일 때 가장 큰 페인트 후보 엔트리를 받을 수 있도록 옵저버를 등록합니다.
< img src = "large_image.jpg" > < p id = 'large-paragraph' > This is large body of text.</ p > ...< script > const observer= new PerformanceObserver(( list) => { let perfEntries= list. getEntries(); let lastEntry= perfEntries[ perfEntries. length- 1 ]; // Process the latest candidate for largest contentful paint }); observer. observe({ entryTypes: [ 'largest-contentful-paint' ]}); </ script >
1.3. 제한 사항
이 섹션은 비규범적입니다.
LargestContentfulPaint API는 휴리스틱에 기반합니다. 따라서 오류가 발생하기 쉽습니다. 다음과 같은 문제가 있습니다:
-
알고리즘은 특정 유형의 사용자 입력을 감지하면 중단됩니다. 하지만 이는 주내용이 표시되기 전에 사용자 입력이 발생하면 알고리즘이 주내용을 포착하지 못함을 의미합니다. 실제로 사용자 입력이 아주 일찍 발생하면 알고리즘은 의미 없는 결과 또는 아무 결과도 내지 않을 수 있습니다.
-
이미지 캐러셀을 고려하여, 콘텐츠가 제거되어도 여전히 가장 큰 것으로 간주됩니다. 이는 큰 콘텐츠를 플레이스홀더로 사용하는 스플래시 스크린이 있는 웹사이트에서 문제를 일으킵니다.
LargestContentfulPaint API는 문서 로드를 기반으로 합니다. 따라서 다음 상황에서 재설정되지 않습니다:
-
Back-forward cache 또는 bfcache 복원.
-
리치 자바스크립트 애플리케이션 내에서 사용되는 동일 문서의 히스토리 탐색.
LargestContentfulPaint API를 사용할 때, 사용자들이 이를 페이지 로드로 간주할 수 있으므로, 이 API 외부에서 이러한 상황을 어떻게 처리할지 고려해야 할 수 있습니다.
또한, 초기에는 화면에 표시되지 않는 페이지(예: 백그라운드 탭 또는 프리렌더링 기술을 통해 로드된 경우)는 로드 시점부터 페인트까지의 시간을 측정하므로 예상보다 더 큰 값을 보고할 수 있으며, 이에 대한 처리 또한 고려해야 합니다.
2. 용어
최대 콘텐츠 렌더 후보는 다음 구성원을 포함하는 구조체입니다:
참고: 최대 콘텐츠풀 페인트 후보의 요소는 DOM에서 제거된 요소가 누수되는 것을 방지하기 위해 약한 참조로 저장할 수 있다.
```3. 가장 큰 콘텐츠 페인트
Largest Contentful Paint는 다음의 새로운 인터페이스를 포함합니다:
3.1. LargestContentfulPaint
인터페이스
[Exposed =Window ]interface :LargestContentfulPaint PerformanceEntry {readonly attribute DOMHighResTimeStamp ;loadTime readonly attribute DOMHighResTimeStamp ;renderTime readonly attribute unsigned long ;size readonly attribute DOMString ;id readonly attribute DOMString ;url readonly attribute Element ?; [element Default ]object (); };toJSON LargestContentfulPaint includes PaintTimingMixin ;
각 LargestContentfulPaint
객체는 다음의 연관 개념을 가진다:
-
size 값, 초기값은 0.
-
loadTime 값, 초기값은 0.
-
id 값, 초기값은 빈 문자열.
-
url 값, 초기값은 빈 문자열.
-
연관된
Element를 담는 element, 초기값은.null
entryType
속성의 getter는 DOMString
을 반환해야 한다.
name
속성의 getter는 빈 문자열을 반환해야 한다.
startTime
속성의 getter는 this의
renderTime
값을 반환해야 한다.
duration
속성의 getter는 0을 반환해야 한다.
renderTime
속성은 기본 paint 타임스탬프 값으로, this의 paint timing
info를 사용하여 반환해야 한다.
loadTime
속성은 this의 loadTime 값을 반환해야 한다.
size
속성은 this의 size 값을 반환해야 한다.
element
속성의 getter는 다음 절차를 수행해야 한다:
-
this의 element가 paint 타이밍에 노출됨이 null로 주어졌을 때 아니면 null을 반환한다.
참고: 위 알고리즘은,
Document의
하위 노드(descendant)가 아닌 요소는,
element
속성 getter에서 반환되지 않음을 정의한다(섀도우 DOM 안의 요소 포함).
이 명세는 Document
에 다음을 추가하여 확장한다:
-
현재 최대 콘텐츠풀 페인트 후보, 즉 최대 콘텐츠풀 페인트 후보 또는 null이며, 초기값은 null이다.
4. 처리 모델
각 Window
는 스크롤 이벤트 발생
여부라는 불리언 값을 가지며, 처음에는 false로 설정됩니다.
4.1. DOM 명세 수정
[DOM] 명세가 갱신되면 이 섹션은 삭제됩니다.
1단계 바로 다음에 다음 단계를 추가합니다:
4.2. 가장 큰 콘텐츠 페인트 보고
Document
document, 페인트 타이밍 정보 paintTimingInfo, 순서가 있는
집합인 대기 중인 이미지 레코드 paintedImages, 그리고 순서가 있는
집합인 요소 paintedTextNodes가 주어졌을 때 최대 콘텐츠풀 페인트를 보고하도록 요청받으면, 다음
단계를 수행한다.
참고: paintedImages의 각 대기 중인 이미지 레코드와 paintedTextNodes의 텍스트 요소는 해당 요소가 페인트 가능(즉, 불투명도와 가시성을 가짐)하고 콘텐츠풀(즉, 이미지 리소스 또는 차단 글꼴이 충분히 로드됨)한 것으로 간주되는 최초의 페인트에 대해 페인트 타이밍 표시에서 정확히 한 번만 보고된다.
-
window를 document의 관련 전역 객체로 둔다.
-
window의 스크롤 이벤트를 디스패치했음 또는 입력 이벤트를 디스패치했음 중 하나가 참이면 반환한다.
-
newCandidate를 document, paintedImages, paintedTextNodes, 그리고 document의 현재 최대 콘텐츠풀 페인트 후보가 주어졌을 때 새 최대 콘텐츠풀 페인트 후보를 계산한 결과로 둔다.
-
newCandidate가 null이면 반환한다.
-
document의 현재 최대 콘텐츠풀 페인트 후보를 newCandidate로 설정한다.
-
entry를 newCandidate, paintTimingInfo, 그리고 document로 LargestContentfulPaint 항목을 생성한 결과로 둔다.
-
entry PerformanceEntry를 큐에 추가한다.
Document
document, 순서가 있는 집합인 대기 중인
이미지 레코드 paintedImages, 순서가 있는
집합인 요소 paintedTextNodes, 그리고 최대
콘텐츠풀 페인트 후보 또는 null인 currentCandidate가 주어졌을 때 새 최대 콘텐츠풀 페인트
후보를 계산하려면, 다음 단계를 수행한다. 이 단계들은 최대 콘텐츠풀 페인트 후보 또는 null을 반환한다.
-
currentSize를 currentCandidate가 null이 아니면 currentCandidate의 크기로, 그렇지 않으면 0으로 둔다.
-
largestSize를 currentSize로 둔다.
-
newCandidate를 null로 둔다.
-
paintedImages의 각 record에 대해 반복한다.
-
imageElement를 record의 요소로 둔다.
-
document가 주어졌을 때 imageElement가 페인트 타이밍에 노출되지 않으면 계속한다.
-
intersectionRect를 imageElement를 대상으로 하고 뷰포트를 루트로 하여 교차 사각형 알고리즘이 반환한 값으로 둔다.
-
result를 intersectionRect와 record의 요청이 주어졌을 때 imageElement의 유효 시각적 크기로 둔다.
-
result가 null이면 계속한다.
-
result의 크기가 largestSize보다 작거나 같으면 계속한다.
-
largestSize를 result의 크기로 설정한다.
-
newCandidate를 다음 값을 갖는 새로운 최대 콘텐츠풀 페인트 후보로 설정한다.
-
-
paintedTextNodes의 각 textNode에 대해 반복한다.
-
document가 주어졌을 때 textNode가 페인트 타이밍에 노출되지 않으면 계속한다.
-
textNode의 알파 채널 값이 <=0이거나 불투명도 값이 <=0이면:
-
textNode의 text-shadow 값이 none이고, textNode의 stroke-color 값이 transparent이며, textNode의 stroke-image 값이 none이면 계속한다.
-
-
intersectionRect를 textNode의 소유한 텍스트 노드 집합에 있는 모든
Text노드의 테두리 상자 합집합을 시각적 뷰포트와 교차한 것으로 둔다. -
result를 intersectionRect와 null이 주어졌을 때 textNode의 유효 시각적 크기로 둔다.
-
result가 null이면 계속한다.
-
result의 크기가 largestSize보다 작거나 같으면 계속한다.
-
largestSize를 result의 크기로 설정한다.
-
newCandidate를 다음 값을 갖는 새로운 최대 콘텐츠풀 페인트 후보로 설정한다.
-
-
newCandidate가 null이 아니고 currentSize가 0보다 크면:
-
newCandidate를 반환한다.
4.3. 요소의 실효 시각 크기 결정
한 Element의 유효 시각적 크기를 결정하려면, 다음 단계를 실행한다.
- 입력
-
intersectionRect,
DOMRectReadOnlyimageRequest,
Request또는 nullelement, Element
document, Document
- 출력
-
유효 시각적 크기 결과. 이는 크기(수), 너비(수), 그리고 높이(수) 항목을 갖는 구조체이며, 최대 콘텐츠풀 페인트에 대해 보고할 유효 시각적 크기, 너비 및 높이를 픽셀 단위로 나타낸다. 요소가 LCP 후보가 되어서는 안 되는 경우에는 null이다.
-
width를 intersectionRect의
width를 가장 가까운 정수로 올림한 값으로 둔다. -
height를 intersectionRect의
height를 가장 가까운 정수로 올림한 값으로 둔다. -
size를
width로 둔다.* height -
root를 document의 브라우징 컨텍스트의 최상위 브라우징 컨텍스트의 활성 문서로 둔다.
-
rootWidth를 스크롤바를 제외한 root의 시각적 뷰포트 너비로 둔다.
-
rootHeight를 스크롤바를 제외한 root의 시각적 뷰포트 높이로 둔다.
-
size가 rootWidth와 rootHeight를 곱한 값과 같으면 null을 반환한다.
-
imageRequest가 null이 아니면, 이미지 위치 및 확대를 조정하기 위해 다음 단계를 실행한다.
-
imageRequest의 응답의 바이트 단위 콘텐츠 길이가 size * 0.004보다 작으면 null을 반환한다.
참고: 이 휴리스틱은 이미지 리소스가 사용자에게 콘텐츠풀한 것으로 보일 만큼 충분한 데이터를 포함하는지 검사한다. 디코딩과 이미지 크기 조정이 적용된 뒤 실제로 생성되는 픽셀 수와 전송된 파일 크기를 비교한다. 매우 적은 바이트로 매우 많은 픽셀을 인코딩하는 이미지는 일반적으로 콘텐츠가 적은 배경이나 그라디언트 등이므로 LCP 후보로 간주되지 않는다.
-
concreteDimensions를 element 내에서 imageRequest의 구체적인 객체 크기로 둔다.
-
visibleDimensions를 object-position 또는 background-position과 element의 콘텐츠 상자에 따른 위치 조정을 적용한 concreteDimensions로 둔다.
참고: 이러한 알고리즘 중 일부는 CSS에서 엄밀하게 정의되어 있지 않다. 예상되는 결과는 element 내 이미지의 실제 위치와 크기를
DOMRectReadOnly로 얻는 것이다. -
clientContentRect를 element의 변환을 적용한 visibleDimensions를 포함하는 가장 작은
DOMRectReadOnly로 둔다. -
intersectingClientContentRect를 clientContentRect와 intersectionRect의 교차 영역으로 둔다.
-
width를 intersectingClientContentRect의
width를 가장 가까운 정수로 올림한 값으로 설정한다. -
height를 intersectingClientContentRect의
height를 가장 가까운 정수로 올림한 값으로 설정한다. -
size를
width로 설정한다.* height참고: 이는 요소의 장식이 아니라 이미지 자체와만 교차하도록 보장한다.
-
naturalArea가 0이면 null을 반환한다.
-
boundingClientArea를
clientContentRect의로 둔다.width* clientContentRect의height -
scaleFactor를
boundingClientArea로 둔다./ naturalArea -
scaleFactor가 1보다 크면 size를 scaleFactor로 나눈다.
-
-
유효 시각적 크기 결과를 반환하며, 크기는 size로, 너비는 width로, 그리고 높이는 height로 설정한다.
-
4.4. LargestContentfulPaint 엔트리 생성
LargestContentfulPaint
항목을
생성하려면, 사용자 에이전트는 다음 단계를 실행해야 한다.
- 입력
-
candidate, 최대 콘텐츠풀 페인트 후보
paintTimingInfo, 페인트 타이밍 정보
document,
Document - 출력
-
-
url을 빈 문자열로 둔다.
-
entry를 document의 관련 렐름을 사용하고, 페인트 타이밍 정보가 paintTimingInfo인 새로운
LargestContentfulPaint항목으로 두며, 다음과 같이 설정한다. -
entry를 반환한다.
-
5. 보안 및 개인정보 보호 고려 사항
이 API는 기본 프리미티브로 Paint Timing을 사용합니다. 유사한 API인 Element Timing과 달리, LCP는 어느 시점까지 가장 큰 요소라면 크기가 작더라도 일부 요소의 타이밍 세부정보를 노출할 수 있습니다. 하지만 이는 Element Timing이 이미 제공하는 정보 이상으로 민감한 정보를 노출하지 않는 것으로 보입니다.