1. 소개
이 섹션은 규범적이지 않습니다.
웹 브라우저의 목적 대부분은 HTML, CSS 및 이미지 리소스를 사용자에게 화면의 픽셀로 변환하는 것입니다. 웹 페이지의 성능을 측정하는 것은 이러한 작업을 수행하는 데 걸리는 시간, 즉 텍스트 또는 이미지 등의 콘텐츠를 화면에 렌더링하는 데 걸리는 시간을 측정하는 경우가 많습니다. 이러한 타이밍을 활용해 페이지의 성능이나 로딩의 사용자 경험에 대해 여러 가지로 말할 수 있지만, 기본적으로 이러한 모든 방법은 시간을 측정하는 공통적인 방법에서 시작합니다.
이 문서는 페인트 타이밍을 일반적인 메커니즘으로 측정하는 방법을 지정하는 기초 문서입니다. 이 기반은 First Paint와 First Contentful Paint 메트릭을 정의하는 데 사용됩니다. 페인트 측정의 다른 구체적 사례는 다른 문서에서 지정될 수 있습니다.
구체적으로, 본 명세는 아래의 내용을 다룹니다:
-
이미지가 디코딩되어 페인팅 준비가 된 시점을 측정
-
요소가 페인팅되는 시점을 측정
-
페인팅된 요소의 크기를 측정
-
페인팅된 요소가 눈에 보이는 콘텐츠를 포함하는지 여부 판단
1.1. 첫 페인트 및 첫 콘텐츠 페인트
로드는 한 순간의 이벤트가 아니라 — 하나의 메트릭으로 온전히 포착할 수 없는 경험입니다. 로드 경험 중 여러 순간이 사용자가 "빠르다" 또는 "느리다"로 인식하는 데 영향을 줄 수 있습니다.
첫 페인트(FP)는 이러한 주요 순간 중 첫 번째이며, 그 다음이 첫 콘텐츠 페인트(FCP)입니다. 이 메트릭들은 브라우저가 주어진 문서를 렌더링하는 시점을 표시합니다. 이는 사용자에게 "지금 화면에 뭔가 나타나고 있는가?"라는 질문에 답이 되므로 중요합니다.
두 메트릭의 주요 차이점은 FP는 브라우저가 주어진 문서에 대해 처음으로 무언가를 렌더링하는 시점을 표시하는 반면, FCP는 브라우저가 DOM에서 이미지 또는 텍스트 콘텐츠의 첫 부분을 렌더링하는 시점을 표시한다는 점입니다.
1.2. 사용 예시
const observer= new PerformanceObserver( function ( list) { const perfEntries= list. getEntries(); for ( const perfEntryof perfEntries) { // 엔트리 처리 // 분석 및 모니터링을 위한 보고 // ... } }); // 페인트 타이밍 알림을 위한 옵저버 등록 observer. observe({ entryTypes: [ "paint" ]});
2. 용어
페인트: 사용자 에이전트가 렌더 트리를 화면의 픽셀로 변환하면 "페인트"(또는 "렌더")를 수행한 것으로 간주한다. 공식적으로, 사용자 에이전트가 렌더링 업데이트 이벤트 루프 단계를 수행했을 때 "렌더링"했다고 본다.
참고: 렌더링 파이프라인은 매우 복잡하며, 타임스탬프는 사용자 에이전트가 이 파이프라인에서 기록할 수 있는 가장 마지막 타임스탬프(최대한의 노력)를 사용해야 한다. 일반적으로 프레임이 OS에 표시를 위해 제출되는 시점이 이 API에 권장된다.
생성된 콘텐츠 가상 요소는 아래 조건이 모두 충족될 때 페인트 가능한 가상 요소이다:
-
의사 요소의 사용된 가시성(visibility) 은
visible입니다. -
의사 요소의 사용된 불투명도(opacity)가 0보다 큽니다.
-
의사 요소가 비어 있지 않은 박스(box)를 생성합니다.
CSS 이미지 img는 아래 조건이 모두 충족될 때 콘텐츠가 있는 이미지이다:
DOMString
은 비어 있지 않음 상태는 문서 공백
문자를 제외한 문자가 하나 이상 포함된 경우다.
요소 target은 아래 중 하나라도 충족되면 콘텐츠 있음이다:
-
target이 텍스트 노드 자식을 가지고 있고, 비어 있지 않은 텍스트를 나타내며, 그 노드의 used opacity가 0보다 크다.
참고: 이는 타이포그래픽 가상 요소가 텍스트 노드의 opacity를 오버라이드하는 경우를 포함한다.
-
target이 background-image로 콘텐츠가 있는 이미지를 가지고 있고, used background-size가 0이 아닌 너비와 높이 값을 가진다.
-
target이
canvas이고, context mode가none이 아닌 값으로 설정됨. -
target이
video요소이고, 대표하는 포스터 프레임 또는 첫 번째 비디오 프레임이 있으며, 그 프레임이 사용 가능하다. -
target이 렌더링된 자손을 가진 SVG 요소이다.
-
target이 가상 요소의 기원 요소이고, 그 가상 요소가 페인트 가능한 가상 요소로서 콘텐츠가 있는 이미지 또는 비어 있지 않은 텍스트를 나타낸다.
요소는 타이밍 대상이 될 수 있는 경우는 아래와 같다:
-
img요소. -
요소에 콘텐츠가 있는 background-image가 있다.
-
텍스트 노드.
페인트 가능한 경계 사각형을 요소 target에 대해 계산하려면 다음 단계를 수행한다:
-
boundingRect를
getBoundingClientRect()를 target에 실행한 결과로 설정한다. -
boundingRect를 반환한다.
참고: overflow 또는 overflow 박스에 포함된 요소는 페인트 가능한 경계 사각형이 클리핑되지 않는다. 두 경우
모두 요소가 스크롤을 통해 표시될 수 있기 때문이다.
요소 el은 아래 조건이 모두 충족될 때 페인트 가능하다:
-
el이 렌더링 중이다.
-
el의 사용된 가시성(visibility) 은
visible입니다. -
el 및 모든 조상 요소의 used opacity가 0보다 크다.
참고:
페인트 가능요소가 사용자에게 실제로 보이지 않는 경우도 있을 수 있다. 예를 들어, 텍스트가 배경색과 같을 때 등이다. 이러한 요소도 첫 콘텐츠 페인트를 계산할 때는 페인트 가능으로 간주한다. -
el의 페인트 가능한 경계 사각형이 문서의 스크롤 영역과 교차한다.
참고: 요소가 크기가 0으로 스케일되거나
display또는: nonedisplay로 설정되어 내용이 빈 사각형일 때를 포함한다.: contents참고: 일반적으로 요소가 뷰포트 내에 있거나, 스크롤 또는 확대/축소로 뷰포트에 들어올 수 있으면 페인트 가능하다.
첫 페인트 엔트리는 DOMHighResTimeStamp
를 포함하고, 이는 사용자 에이전트가 내비게이션 후 처음으로 렌더링한 시점을 보고한다. 기본 배경 페인트는 제외하지만, 비기본 배경 페인트와 iframe의 외곽 박스는 포함한다. 이는 페이지
로드에서 개발자가 가장 중요하게 여기는 첫 순간으로, 사용자 에이전트가 페이지 렌더링을 시작한 시점이다.
브라우징 컨텍스트 ctx는 아래 조건 중 하나라도 충족되면 페인트 타이밍 대상이다:
-
ctx가 최상위 브라우징 컨텍스트일 때.
-
ctx가 중첩 브라우징 컨텍스트이고, 사용자 에이전트가 ctx에 대해 페인트 타이밍 보고를 설정한 경우.
참고: 이는 사용자 에이전트가 원한다면 메인 프레임 외에도 일부 프레임에만 페인트 타이밍을 활성화할 수 있도록 한다. 예를 들어, 사용자 에이전트가 교차 출처 iframe에 대해 페인트 타이밍을 비활성화하도록 결정할 수 있는데, 일부 상황에서는 해당 프레임의 페인트 타이밍이 메인 프레임의 정보를 노출할 수 있기 때문이다.
3. 페인트 타이밍 믹스인
이 섹션은 비규범적입니다.
PaintTimingMixin
인터페이스는 렌더링 주기와 관련된 타임스탬프를 노출합니다.
이는 플랫폼 객체에 포함되며, PerformanceEntry를
확장합니다.
특히 PerformanceElementTiming,
LargestContentfulPaint,
PerformanceEventTiming,
PerformancePaintTiming,
그리고 PerformanceLongAnimationFrameTiming에
의해 사용됩니다.
paintTime
속성은 렌더링 업데이트 루프의 끝에서의 타임스탬프를 나타내며,
presentationTime
은 프레임이 사용자에게 표시될 때 구현별로 지정된 타임스탬프를 나타냅니다.
HTML 표준의 페인트 타이밍 마크
알고리즘은
렌더링 업데이트 호출에서 두 속성을 채웁니다.
페인트 타이밍에 의존하는 항목의 속성, 예를 들어 LargestContentfulPaint의
renderTime
(및 startTime),
은 보통 특정 타임스탬프 대신 기본 페인트 타임스탬프를 반환합니다.
이는 presentationTime의
구현별 특성을 무시하게 만듭니다.
3.1. PaintTimingMixin
인터페이스
[Exposed =Window ]interface mixin {PaintTimingMixin readonly attribute DOMHighResTimeStamp ;paintTime readonly attribute DOMHighResTimeStamp ?; };presentationTime
PaintTimingMixin
인터페이스 믹스를 포함하는 객체는 페인트 타이밍 정보 (null
또는 페인트 타이밍 정보)를 가집니다.
페인트 타이밍 정보는 구조체입니다. 다음과 같은 항목들을 가집니다:
- 렌더링 업데이트 종료 시간
- 구현 정의된 표시 시간
-
null 또는
DOMHighResTimeStamp
paintTime
속성의 getter 단계는 this의 페인트 타이밍 정보의 렌더링 업데이트 종료 시간을 반환하는 것입니다.
presentationTime
속성의 getter 단계는 존재한다면 this의 페인트 타이밍
정보의 구현 정의된 표시 시간을 반환하는 것입니다.
기본 페인트 타임스탬프를 페인트 타이밍 정보 paintTimingInfo에 대해 가져오기 위해, paintTimingInfo의 구현 정의된 표시 시간이 null이 아니라면 반환하고, 그렇지 않으면 paintTimingInfo의 렌더링 업데이트 종료 시간을 반환합니다.
4. PerformancePaintTiming
인터페이스
[Exposed =Window ]interface :PerformancePaintTiming PerformanceEntry { [Default ]object (); };toJSON PerformancePaintTiming includes PaintTimingMixin ;
PerformancePaintTiming
인터페이스는 PerformanceEntry
인터페이스의 다음 속성들을 확장합니다:
-
name속성의 getter는 최소 프레임 특성을 위한DOMString을 반환해야 합니다. name의 가능한 값은 다음과 같습니다:-
: 첫 번째 페인트에 사용됩니다."first-paint" -
: 첫 번째 의미 있는 페인트에 사용됩니다."first-contentful-paint"
-
-
entryType속성의 getter는를 반환해야 합니다."paint" -
startTime속성의 getter는 페인트가 발생한 시간을 나타내는DOMHighResTimeStamp를 반환해야 합니다. -
duration속성의 getter는 0을 반환해야 합니다. -
toJSON이 호출되면,
PerformancePaintTiming에 대해 기본 toJSON 단계를 실행합니다.
NOTE: PerformancePaintTiming
을 구현하는 사용자 에이전트는 글로벌 객체의 를 supportedEntryTypes
에 포함해야 하며, 해당 브라우징 컨텍스트가 paint-timing eligible일 경우에 해당됩니다.
이를 통해 개발자는 특정 브라우징 컨텍스트에 대해 페인트 타이밍 지원 여부를 감지할 수 있습니다.
5. 처리 모델
5.1. 연관된 이미지 요청
각 Element
는 연관된 이미지 요청을
가지며, 이는 이미지 요청이거나 null이며, 초기값은 null입니다.
만약 Element
element가
HTMLImageElement,
SVGImageElement,
또는 HTMLVideoElement
타입일 때,
새로운 이미지 리소스(예: 이미지 또는 포스터 이미지로 표시될 이미지 리소스)를 생성하면
element의 연관된 이미지 요청은 생성된 이미지 리소스의 이미지
요청으로 설정됩니다.
Note: "data" 스킴과 동일한 URL에서 가져온 모든 이미지 리소스는 이미지 요청을 가지며,
이는 네트워크 요청 없이 로드되어야 하지만, 여전히 로딩이 필요합니다. 이러한 요청은 Element
의 연관된 이미지
요청이 될 수 있습니다.
Note: 현재 언어는 특정 알고리즘을 명시하지 않아 다소 모호합니다. 해당 처리 모델이 더 통합된 형태가 되면 이를 더 엄격하게 정의할 수 있습니다.
모든 Element
는 연관된
배경 이미지 요청 목록(초기에는 빈 배열)을 가집니다. Element
element의 스타일에 의해 새로운 이미지 리소스(배경 이미지로 표시될)가 필요할 때, 새 리소스가 생성한 이미지
요청이 element의 연관된 배경 이미지 요청 목록에 추가됩니다.
NOTE: Element
는 여러 개의 이미지 요청을 가질 수 있습니다. 예를 들어, background-image 속성에 여러 값이 있을 때 입니다. 아래 예시처럼 하나의 background-image 속성이 네 개의 이미지
요청을 생성하고, 각각은 아래 알고리즘에 의해 기록 및 보고됩니다.
<!DOCTYPE html> < style > div { background-image : url( https://images.example/background1.png ), url( https://images.example/background2.png ); } </ style > < div ></ div > < div ></ div >
5.2. 페인트 타이밍 기록
pending image record는 다음과 같은 구조체의 항목들을 가진 구조체입니다:
-
element,
Element -
request, 이미지 요청
-
loadTime,
DOMHighResTimeStamp
Element
는 소유 텍스트 노드
집합을 가지며, 이는 순서 집합의 Text
노드들로, 초기값은 빈 집합이다.
Document
는 이전에 보고된
페인트 집합을 가지며, 이는 순서 집합의 문자열로, 초기값은 빈 집합이다.
Document
는 렌더링 대기
이미지들을 가지며, 이는 리스트의 대기 중인 이미지 기록으로, 초기값은 빈 리스트이다.
Document
는 렌더링된
텍스트를 가진 요소 집합을 가지며, 이는 순서 집합의 Element들로,
초기값은 빈 집합이다.
5.2.1. CSS 명세의 수정 사항
이미지 요청이 Element
element의 연관 배경 이미지 요청에 있고 완전히 사용 가능해지면,
element와 이미지
요청을 입력값으로 로딩이 완료된 이미지를 처리 알고리즘을 실행한다.
5.2.2. HTML 명세의 수정 사항
Element
element의 연결된 이미지 요청이 완전히 사용 가능하게
되면, element와 그 연결된 이미지 요청을 입력값으로 하여 로딩이
완료된 이미지를 처리하는 알고리즘을 실행한다.
Text
노드 text를 처음으로 페인트할 때, 다음 단계를 수행해야 한다:
-
text가 폰트 페이스가 폰트 블록 기간에 있기 때문에 페인트되지 않는 경우, 반환한다.
-
Append text를 element의 소유 텍스트 노드 집합에 추가한다.
5.2.3. 로딩이 완료된 이미지 처리
Element
element와 image request imageRequest를 입력값으로 가진다:
-
root를 element의 루트로 한다.
-
root가
Document가 아니면 return. -
now를 현재 고해상도 시간으로, element의 관련 글로벌 오브젝트를 기준으로 한다.
-
record를 대기 중인 이미지 기록으로, element element, request imageRequest, loadTime now를 가진다.
-
record를 root의 렌더링 대기 이미지들에 추가한다.
5.3. 페인트 타이밍 보고
5.3.1. 첫 콘텐츠 페인트
-
document의 이전에 보고된 페인트 집합에
가 포함되어 있으면 false를 반환한다."first-contentful-paint" -
document에 요소가 하나 이상 존재하고, 그 요소가 페인트 가능이면서 콘텐츠 있음이라면 true를 반환한다.
-
그 외에는 false를 반환한다.
5.3.2. 페인트 타이밍 표시
-
document의 브라우징 컨텍스트가 페인트 타이밍 대상이 아니면 return.
-
paintTimingInfo를 새 페인트 타이밍 정보로 설정하고, 그 렌더링 업데이트 종료 시점은 document의 현재 고해상도 시간으로 한다.
-
paintedImages를 새 순서 집합으로 한다.
-
paintedTextNodes를 새 순서 집합으로 한다.
-
doc의 렌더링 대기 이미지들 리스트의 각 record에 대해:
-
record의 request가 사용 가능하며 페인트 준비가 되었다면, 아래 단계를 실행한다:
-
record를 paintedImages에 추가한다.
-
record를 doc의 렌더링 대기 이미지들 리스트에서 제거한다.
-
-
-
Elementelement를 doc의 모든 자손에 대해 반복한다:-
element이 doc의 렌더링된 텍스트가 있는 요소 집합에 포함되어 있다면, 계속 진행한다.
-
element의 소유 텍스트 노드 집합이 비어 있다면, 계속 진행한다.
-
Append element를 doc의 렌더링된 텍스트가 있는 요소 집합에 추가한다.
-
Append element를 paintedTextNodes에 추가한다.
-
-
reportedPaints를 document의 이전에 보고된 페인트 집합으로 한다.
-
frameTimingInfo를 document의 현재 프레임 타이밍 정보로 한다.
-
document의 현재 프레임 타이밍 정보를 null로 설정한다.
-
flushPaintTimings를 아래 단계로 정의한다:
-
reportedPaints에
가 없고, 사용자 에이전트가 첫 페인트를 표시하도록 설정되어 있으면, 페인트 타이밍 보고를 document,"first-paint" , paintTimingInfo로 실행한다."first-paint" 참고: 첫 페인트는 기본 배경 페인트를 제외하지만, 비기본 배경 페인트는 포함한다.
-
document가 첫 콘텐츠 페인트를 보고해야 하는지라면:
-
페인트 타이밍 보고를 document,
, paintTimingInfo로 실행한다."first-contentful-paint"
참고: 부모 프레임은 자식 iframe의 페인트 이벤트를, 자식 프레임은 부모의 페인트 이벤트를 인지하면 안 된다. 즉, iframe만 포함된 프레임은 첫 페인트(iframe의 외곽 박스 때문에)는 있지만 첫 콘텐츠 페인트는 없다.
참고: document는
나"first-paint" 가 반드시 표시되는 것은 아니다. 완전히 빈 document는 첫 페인트를 표시하지 않을 수 있고, document가 콘텐츠가 없는 요소만 포함할 경우 첫 콘텐츠 페인트를 표시하지 않을 수 있다."first-contentful-paint" 참고: 첫 페인트 표시는 선택적이다. 페인트 타이밍을 구현하는 사용자 에이전트는 최소한 첫 콘텐츠 페인트는 표시해야 한다.
-
-
최대 콘텐츠 페인트 보고를 document, paintTimingInfo, paintedImages, paintedTextNodes로 실행한다.
-
요소 타이밍 보고를 document, paintTimingInfo, paintedImages, paintedTextNodes로 실행한다.
-
frameTimingInfo가 null이 아니면, 긴 애니메이션 프레임 엔트리 큐를 document, frameTimingInfo, paintTimingInfo로 실행한다.
-
-
사용자 에이전트가 구현 정의 표시 시점을 지원하지 않으면 flushPaintTimings를 호출하고 return.
-
다음 단계를 병렬로 실행한다:
-
현재 프레임이 사용자에게 표시될 때까지 구현 정의된 시간만큼 기다린다.
-
paintTimingInfo의 구현 정의 표시 시점을 document의 현재 고해상도 시간으로 설정한다.
-
document의 크로스 오리진 격리 능력이 false이면:
-
paintTimingInfo의 구현 정의 표시 시점을 4ms 또는 그보다 더 큰 배수로 올림한다.
-
현재 고해상도 시간이 paintTimingInfo의 구현 정의 표시 시점이 될 때까지 기다린다.
-
-
글로벌 태스크 큐를 성능 타임라인 태스크 소스로 document의 관련 글로벌 오브젝트에 flushPaintTimings를 실행하도록 추가한다.
-
5.3.3. 페인트 타이밍 보고
-
document의 관련 Realm에서 새로운
PerformancePaintTiming객체 newEntry를 생성하고, 그 속성을 다음과 같이 설정한다:-
newEntry의
name속성을 paintType으로 설정한다. -
newEntry의
entryType속성을로 설정한다."paint" -
newEntry의
startTime속성을 paintTimingInfo가 주어졌을 때의 기본 페인트 타임스탬프로 설정한다. -
newEntry의
duration속성을 0으로 설정한다.
-
-
newEntry의 페인트 타이밍 정보를 paintTimingInfo로 설정한다.
-
Append paintType을 document의 이전에 보고된 페인트 집합에 추가한다.
5.4. 공통 알고리즘
5.4.1. 페인트 타이밍에 노출됨
Element element가 페인트 타이밍에 노출됨인지 판단하려면, Document 또는 null document를 받아서 다음 단계를 수행한다:
-
element가 connected가 아니면 false를 반환한다.
-
document가 null이면, document를 element의 relevant settings object의 relevant global object의 associated document로 한다.
-
document가 완전히 활성화됨이 아니면 false를 반환한다.
-
element의 루트가 document와 다르면 false를 반환한다.
-
true를 반환한다.
6. 감사의 글
이 명세 개선을 위해 기술적 의견과 제안을 해준 모든 기여자에게 특별히 감사드립니다.