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는 휴리스틱 기반이므로 오류 가능성이 있습니다. 다음과 같은 문제가 있습니다:
-
알고리즘은 특정 유형의 사용자 입력을 감지하면 중단됩니다. 그러나 이는 사용자가 입력을 메인 콘텐츠가 표시되기 전에 하는 경우, 알고리즘이 실제 메인 콘텐츠를 포착하지 못할 수 있음을 의미합니다. 실제로 입력이 매우 일찍 발생하면 의미 없는 결과를 내거나 결과가 나오지 않을 수도 있습니다.
-
이미지 캐러셀을 감안하여, 콘텐츠가 제거되어도 가장 큰 것으로 간주됩니다. 이는 대체 콘텐츠로 큰 콘텐츠를 사용하는 스플래시 스크린이 포함된 웹사이트에서 문제가 될 수 있습니다.
2. 용어
largest contentful paint 후보는 구조체로, 다음 구성원을 포함합니다:
largest contentful paint 후보 candidate는 다음 조건을 만족하면 largest contentful paint로 적격입니다:
-
candidate의 element의 투명도가 0보다 큼
-
candidate의 element가 텍스트 노드이거나, candidate의 request의 response의 바이트 단위 콘텐츠 길이가 candidate의 element의 실효 시각 크기 * 0.004 이상임
참고: 이 휴리스틱은 이미지 리소스가 사용자가 내용이 있다고 인식할 만한 충분한 데이터를 담고 있는지 테스트합니다. 이는 전송 파일 크기와 실제로 생성되는 픽셀 수(디코딩 및 이미지 스케일 적용 후)를 비교합니다. 매우 적은 바이트로 아주 많은 픽셀을 인코딩하는 이미지는 주로 저내용 배경, 그라디언트 등이며, largest contentful paint 후보로 간주되지 않습니다.
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
값이 0이 아니면 그 값을, 아니면 loadTime 값을 반환해야 합니다.
duration
속성 getter는 0을 반환해야 합니다.
renderTime
속성은 default paint timestamp를 this의 paint timing
info로 반환해야 합니다.
loadTime
속성은 this의 loadTime 값을 반환해야 합니다.
size
속성은 this의 size 값을 반환해야 합니다.
url
속성은 this의 url
값을 반환해야 합니다.
element
속성 getter는 다음 단계를 수행해야 합니다:
-
this의 element가 null을 기준으로 페인트 타이밍에 노출됨이 아니라면, null을 반환.
참고: 위 알고리즘은 트리의
자손이 아닌 요소(Shadow DOM 내부 요소 포함)는 element
속성 getter에서 반환하지 않음을 정의합니다.
이 명세는 Document
에도 largest
contentful paint size라는 개념을 추가하며, 처음에는 0으로 설정됩니다.
또한 연관된 content set도 추가하며,
처음에는 빈 셋입니다. content set은
(Element,
Request)
튜플로 채워집니다. 이는
알고리즘이 각 콘텐츠를 한 번만 고려하도록 성능상 사용됩니다.
참고: 사용자 에이전트는 content set을 유지하여 제거된 콘텐츠가 메모리 누수를 일으키지 않게 해야 합니다. 특히,
튜플들의 생명주기를 Elements에
대한 약 참조에 묶어, 요소가 삭제된 이후에 정리할 수 있도록 해야 합니다. 이 셋은 웹 개발자에게 노출되지 않으므로 가비지
컬렉션 시점을 노출하지 않습니다.
4. 처리 모델
각 Window
는 스크롤 이벤트 발생
여부라는 불리언 값을 가지며, 처음에는 false로 설정됩니다.
4.1. DOM 명세 수정
[DOM] 명세가 갱신되면 이 섹션은 삭제됩니다.
1단계 바로 다음에 다음 단계를 추가합니다:
4.2. 가장 큰 콘텐츠 페인트 보고
Document
document, 페인트 타이밍 정보 paintTimingInfo, 순서 있는 집합 형태의 보류 중인 이미지 레코드 paintedImages, 그리고 순서 있는
집합 형태의 요소 paintedTextNodes가 주어지면, 다음 단계를 수행한다:
-
각 paintedImages의 record에 대해:
-
imageElement를 record의 element로 지정합니다.
-
imageElement가 document에 대해 페인트 타이밍에 노출되지 않은 경우, 다음으로 진행합니다.
-
request를 record의 request로 지정합니다.
-
candidate를 (imageElement, request)로 지정합니다.
-
intersectionRect를 imageElement를 대상으로, viewport를 루트로 사용하는 intersection rect 알고리즘의 반환값으로 지정합니다.
-
LargestContentfulPaint 엔트리 잠재적으로 추가를 candidate, intersectionRect, paintTimingInfo, record의 loadTime, document와 함께 호출합니다.
-
-
각 paintedTextNodes의 textNode에 대해,
-
textNode가 document에 대해 페인트 타이밍에 노출되지 않은 경우, 다음으로 진행합니다.
-
textNode가 알파 채널 값이 0 이하이거나 투명도 값이 0 이하인 경우:
-
textNode의 text-shadow 값이 none이고, textNode의 stroke-color 값이 transparent이며 textNode의 stroke-image 값이 none이면, 다음으로 진행합니다.
-
-
candidate를 (textNode, null)로 지정합니다.
-
intersectionRect를 빈 사각형으로 지정합니다.
-
각
Textnode text가 textNode의 set of owned text nodes에 있을 때:-
intersectionRect를 text의 border box와 intersectionRect를 포함하는 가장 작은 사각형으로 확장합니다.
-
-
intersectionRect와 시각적 뷰포트를 교집합합니다.
-
LargestContentfulPaint 엔트리 잠재적으로 추가를 candidate, intersectionRect, paintTimingInfo, 0, document와 함께 호출합니다.
-
4.3. 요소의 실효 시각 크기 결정
Element의 실효 시각 크기를 결정하기 위해 다음 단계를 수행합니다:
- 입력
-
intersectionRect,
DOMRectReadOnlyimageRequest,
Requestelement, Element
document, Document
- 출력
-
Largest Contentful Paint용 보고 크기(픽셀). 후보가 되지 않으면 null을 반환합니다.
-
width를 intersectionRect의
width로 설정합니다. -
height를 intersectionRect의
height로 설정합니다. -
size를
width로 설정합니다.* height -
root를 document의 탐색 컨텍스트의 최상위 탐색 컨텍스트의 활성 문서로 설정합니다.
-
rootWidth를 root의 비쥬얼 뷰포트의 가로 길이(스크롤바 제외)로 설정합니다.
-
rootHeight를 root의 비쥬얼 뷰포트의 세로 길이(스크롤바 제외)로 설정합니다.
-
size가 rootWidth × rootHeight와 같으면 null 반환.
-
imageRequest가 largest contentful paint 적격이 아니라면 null 반환.
-
imageRequest가 null이 아니면, 이미지 위치와 업스케일링을 반영해 다음 단계를 수행합니다:
-
concreteDimensions를 imageRequest의 구체 객체 크기(element 내)로 설정합니다.
-
visibleDimensions를 concreteDimensions로 하되, object-position 또는 background-position 및 element의 content box에 따라 위치를 조정합니다.
참고: 일부 알고리즘은 CSS에서 엄격하게 정의되어 있지 않습니다. 기대 결과는 element 내 실제 이미지의 위치와 크기를
DOMRectReadOnly로 얻는 것입니다.-
clientContentRect를 element의 변형(transform)을 적용한 visibleDimensions를 포함하는 가장 작은
DOMRectReadOnly로 설정합니다. -
intersectingClientContentRect를 clientContentRect와 intersectionRect의 교집합으로 설정합니다.
-
size를
intersectingClientContentRect의로 설정합니다.width* intersectingClientContentRect의height
참고: 이는 실제 이미지 자체만 교집합 대상이 되어 요소 장식이 포함되지 않도록 보장합니다.
-
naturalArea를
imageRequest의 원본 너비(natural width)로 설정합니다.* imageRequest의 원본 높이(natural height) -
naturalArea가 0이면 null 반환.
-
boundingClientArea를
clientContentRect의로 설정합니다.width* clientContentRect의height -
scaleFactor를
boundingClientArea로 설정합니다./ naturalArea -
scaleFactor가 1보다 크면 size를 scaleFactor로 나눕니다.
-
-
size 반환.
-
4.4. LargestContentfulPaint 엔트리 잠재적 추가
참고: Largest Contentful Paint API를 구현하는 User Agent는 를 supportedEntryTypes에
Window
컨텍스트에서 포함해야 합니다.
이를 통해 개발자는 해당 API 지원 여부를 확인할 수 있습니다.
LargestContentfulPaint 엔트리 잠재적으로 추가를 위해, User Agent는 다음 단계를 수행해야 합니다:
- 입력
-
candidate, largest contentful paint 후보
intersectionRect,
DOMRectReadOnlypaintTimingInfo, paint timing info
loadTime, DOMHighResTimestamp
document, Document
- 출력
-
없음
-
document의 content set이 candidate를 포함하면 반환합니다.
-
window를 document의 관련 전역 객체로 설정합니다.
-
window의 스크롤 이벤트 발생 여부 또는 입력 이벤트 발생 여부 중 하나라도 true이면 반환.
-
size를 intersectionRect 기준 실효 시각 크기(candidate의 element)로 설정합니다.
-
size가 document의 largest contentful paint size 이하이면 반환합니다.
-
url을 빈 문자열로 설정합니다.
-
candidate의 request가 null이 아니면, url을 해당 request URL로 설정합니다.
-
id를 candidate의 element의 element id로 설정합니다.
-
contentInfo를 map으로 하여, contentInfo["size"] = size, contentInfo["url"] = url, contentInfo["id"] = id, contentInfo["loadTime"] = loadTime, contentInfo["element"] = candidate의 element로 설정합니다.
-
LargestContentfulPaint 엔트리 생성를 contentInfo, paintTimingInfo, document를 인자로 호출합니다.
-
4.5. LargestContentfulPaint 엔트리 생성
LargestContentfulPaint 엔트리 생성을 위해, User Agent는 다음 단계를 수행해야 합니다:
- 입력
-
contentInfo, map
paintTimingInfo, paint timing info
document,
Document - 출력
-
없음
-
document의 largest contentful paint size를 contentInfo["size"]로 설정합니다.
-
entry를 관련 realm을 가진 새로운
LargestContentfulPaintentry로 하며, paint timing info는 paintTimingInfo로 지정하고, -
PerformanceEntry entry를 큐에 넣습니다.
-
5. 보안 및 개인정보 보호 고려 사항
이 API는 기본 프리미티브로 Paint Timing을 사용합니다. 유사한 API인 Element Timing과 달리, LCP는 어느 시점까지 가장 큰 요소라면 크기가 작더라도 일부 요소의 타이밍 세부정보를 노출할 수 있습니다. 하지만 이는 Element Timing이 이미 제공하는 정보 이상으로 민감한 정보를 노출하지 않는 것으로 보입니다.