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에 권장된다.
생성된 콘텐츠 가상 요소는 아래 조건이 모두 충족될 때 페인트 가능한 가상 요소이다:
-
가상 요소의 used visibility가
visible
이다. -
가상 요소가 비어 있지 않은 박스를 생성한다.
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의 used visibility가
visible
이다. -
el 및 모든 조상 요소의 used opacity가 0보다 크다.
참고:
페인트 가능
요소가 사용자에게 실제로 보이지 않는 경우도 있을 수 있다. 예를 들어, 텍스트가 배경색과 같을 때 등이다. 이러한 요소도 첫 콘텐츠 페인트를 계산할 때는 페인트 가능으로 간주한다. -
el의 페인트 가능한 경계 사각형이 문서의 스크롤 영역과 교차한다.
참고: 요소가 크기가 0으로 스케일되거나
display
또는: nonedisplay
로 설정되어 내용이 빈 사각형일 때를 포함한다.: contents참고: 일반적으로 요소가 뷰포트 내에 있거나, 스크롤 또는 확대/축소로 뷰포트에 들어올 수 있으면 페인트 가능하다.
첫 페인트 엔트리는 DOMHighResTimeStamp
를 포함하고, 이는 사용자 에이전트가 내비게이션 후 처음으로 렌더링한 시점을 보고한다. 기본 배경 페인트는 제외하지만, 비기본 배경 페인트와 iframe의 외곽 박스는 포함한다. 이는 페이지
로드에서 개발자가 가장 중요하게 여기는 첫 순간으로, 사용자 에이전트가 페이지 렌더링을 시작한 시점이다.
브라우징 컨텍스트 ctx는 아래 조건 중 하나라도 충족되면 페인트 타이밍 대상이다:
-
ctx가 최상위 브라우징 컨텍스트일 때.
-
ctx가 중첩 브라우징 컨텍스트이고, 사용자 에이전트가 ctx에 대해 페인트 타이밍 보고를 설정한 경우.
참고: 이는 사용자 에이전트가 원한다면 메인 프레임 외에도 일부 프레임에만 페인트 타이밍을 활성화할 수 있도록 한다. 예를 들어, 사용자 에이전트가 교차 출처 iframe에 대해 페인트 타이밍을 비활성화하도록 결정할 수 있는데, 일부 상황에서는 해당 프레임의 페인트 타이밍이 메인 프레임의 정보를 노출할 수 있기 때문이다.
3. 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의 가능한 값은 다음과 같다: -
entryType
속성의 getter는
를 반환해야 한다."paint" -
startTime
속성의 getter는 페인트가 발생한 시점의DOMHighResTimeStamp
를 반환해야 한다. -
duration
속성의 getter는 0을 반환해야 한다. -
toJSON이 호출되면, 기본 toJSON 단계를
PerformancePaintTiming
에 대해 실행한다.
참고: PerformancePaintTiming
을 구현하는 사용자 에이전트는
를 supportedEntryTypes
에
포함해야 하며, 글로벌 오브젝트의 브라우징 컨텍스트가 페인트 타이밍 대상일 때 해당한다.
이를 통해 개발자는 특정 브라우징 컨텍스트의 페인트 타이밍 지원 여부를 감지할 수 있다.
5. 처리 모델
5.1. 연관 이미지 요청
Element
는 연관 이미지 요청을
가지며, 이는 이미지 요청 또는 null이다. 기본값은 null.
Element
element가 HTMLImageElement
,
SVGImageElement
,
또는 HTMLVideoElement
타입일 때, 새로운 이미지 리소스가 생성되면(예: 이미지 또는 포스터 이미지 표시) element의 연관 이미지 요청을 생성된 이미지 리소스의 이미지 요청으로 설정한다.
참고: URL의 scheme이
"data"인 경우, 모든 이미지 리소스는 가져오지 않아도 이미지
요청을 갖는다. 이 요청도 Element
의
연관 이미지
요청이 될 수 있다.
참고: 현재 언어는 구체적인 알고리즘을 지칭하지 않으므로 모호하다. 해당 처리 모델이 더 통합될 때 보다 엄밀하게 만들 수 있다.
Element
는 연관 배경
이미지 요청 리스트를 가지며, 초기값은 빈 배열이다. Element
element의 스타일이 새로운 이미지 리소스를 필요로 할 때(배경 이미지 표시), 새 리소스에서 생성된 이미지
요청을 element의 연관 배경 이미지 요청에 추가한다.
참고: Element
는 여러 이미지 요청을 가질 수 있다. 예를 들어 background-image 속성에 여러 값이 있는 경우다. 아래 예시에서 하나의 background-image 속성이 4개의 이미지
요청을 생성하며, 각각의 요청은 아래 알고리즘에 의해 기록 및 보고된다.
<!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. 페인트 타이밍 기록
대기 중인 이미지 기록은 다음 구조체의 항목을 가진다:
-
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의 렌더링 대기 이미지들 리스트에서 제거한다.
-
-
-
Element
element를 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. 감사의 글
이 명세 개선을 위해 기술적 의견과 제안을 해준 모든 기여자에게 특별히 감사드립니다.