요소 타이밍 API

편집자 초안,

이 문서에 대한 자세한 내용
이 버전:
https://w3c.github.io/element-timing/
테스트 스위트:
https://github.com/web-platform-tests/wpt/tree/master/element-timing
이슈 추적:
GitHub
편집자:
(Google)
(Google)
전 편집자:
(Google)

초록

이 문서는 크거나 개발자가 지정한 이미지 요소 및 텍스트 노드가 화면에 표시되는 시점을 모니터링할 수 있게 하는 API를 정의합니다.

이 문서의 상태

이는 편집자 초안의 공개 사본입니다. 논의를 위해서만 제공되며 언제든 변경될 수 있습니다. 여기에 게시되었다고 해서 W3C가 그 내용을 승인한다는 의미는 아닙니다. 진행 중인 작업 이외의 용도로 이 문서를 인용하지 마십시오.

GitHub Issues는 이 명세에 대한 논의에 선호됩니다.

이 문서는 2025년 8월 18일 W3C Process Document의 적용을 받습니다.

1. 소개

이 절은 비규범적입니다.

중요한 요소가 화면에 표시되는 시점을 아는 것은 페이지 로드 성능을 이해하는 데 핵심적입니다. 필수 구성요소의 빠른 렌더링만으로 만족스러운 로딩 경험이 충분히 보장되는 것은 아니지만, 이는 필요합니다. 따라서 이러한 렌더링 타임스탬프를 모니터링하는 것은 페이지 로드를 개선하고 회귀를 방지하는 데 중요합니다.

이 명세는 개발자와 분석 제공자에게 중요한 요소의 렌더링 타임스탬프를 측정하는 API를 제공합니다. 현재 실제 사용자에 대해 이러한 타임스탬프를 측정할 좋은 방법은 없습니다. 기존 접근 방식은 관찰자를 너무 일찍 등록하거나 상당한 DOM 조작을 필요로 합니다. 이러한 접근 방식은 § 4 보안 및 개인정보 보호 고려사항 절에서 논의됩니다.

웹 개발자는 자신의 사이트에서 중요한 사용자 상호작용의 전문가이므로, 자신이 관심을 가지는 요소가 무엇인지 사용자 에이전트에 알릴 수 있어야 합니다. 따라서 이 API는 웹 개발자가 주석을 단 요소에 대한 렌더링 타이밍 정보를 노출합니다.

1.1. 노출되는 요소

Element Timing API는 타이밍 적격 요소에 대한 타이밍 정보를 지원하며, 이는 [PAINT-TIMING]에서 정의됩니다.

"elementtiming" 콘텐츠 속성을 가진 요소는 이미지 요소 타이밍 보고텍스트 요소 타이밍 보고 알고리즘에서 보고됩니다.

1.2. 사용 예제

다음 예제는 elementtiming 속성을 통해 관찰 대상으로 등록된 이미지와, 타이밍 정보를 수집하는 관찰자를 보여줍니다.

<img... elementtiming='foobar'/>
<p elementtiming='important-paragraph'>이것은 내가 관심 있는 텍스트입니다.</p>
...
<script>
const observer = new PerformanceObserver((list) => {
  let perfEntries = list.getEntries();
  // 항목을 반복하면서 처리합니다.
});
observer.observe({type: 'element', buffered: true});
</script>

다음은 이 API를 사용해 렌더링 타임스탬프를 측정할 수 있고, 페이지 탐색과 비교해야 하는 요소의 예입니다:

이 API는 렌더링 타임스탬프를 입력 타임스탬프와 비교함으로써 페이지 로드 외의 사용 사례도 가질 수 있습니다. 예를 들어 개발자는 위젯을 트리거하는 클릭 이후 해당 위젯이 표시되는 데 걸리는 시간을 모니터링할 수 있습니다.

2. 요소 타이밍

요소 타이밍은 다음 새 인터페이스를 포함합니다:

2.1. PerformanceElementTiming 인터페이스

[Exposed=Window]
interface PerformanceElementTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp renderTime;
    readonly attribute DOMHighResTimeStamp loadTime;
    readonly attribute DOMRectReadOnly intersectionRect;
    readonly attribute DOMString identifier;
    readonly attribute unsigned long naturalWidth;
    readonly attribute unsigned long naturalHeight;
    readonly attribute DOMString id;
    readonly attribute Element? element;
    readonly attribute USVString url;
    [Default] object toJSON();
};

PerformanceElementTiming includes PaintTimingMixin;

PerformanceElementTiming 객체는 하나의 연결된 요소에 대한 타이밍 정보를 보고합니다.

PerformanceElementTiming 객체는 다음 연결된 개념을 가지며, 모두 처음에는 null로 설정됩니다:

PerformanceElementTiming의 연결된 개념 및 일부 속성은 § 3.3 이미지 요소 타이밍 보고§ 3.4 텍스트 요소 타이밍 보고의 처리 모델에서 지정됩니다.

entryType 속성의 getter는 DOMString "element"를 반환해야 합니다.

name 속성의 getter는 초기화된 값을 반환해야 합니다.

startTime 속성의 getter는 thisrenderTime이 0이 아니면 그 값을, 그렇지 않으면 thisloadTime 값을 반환해야 합니다.

duration 속성의 getter는 0을 반환해야 합니다.

renderTime 속성 getter 단계는 thispaint timing info가 주어졌을 때 기본 페인트 타임스탬프를 반환하는 것입니다.

loadTime 속성의 getter는 초기화된 값을 반환해야 합니다.

intersectionRect 속성은 초기화된 값을 반환해야 합니다.

identifier 속성의 getter는 초기화된 값을 반환해야 합니다.

naturalWidth 속성은 초기화된 값을 반환해야 합니다.

naturalHeight 속성은 초기화된 값을 반환해야 합니다.

id 속성의 getter는 초기화된 값을 반환해야 합니다.

element 속성의 getter는 다음 단계를 수행해야 합니다:

  1. thiselement가 null이 주어졌을 때 페인트 타이밍에 노출되지 않으면 null을 반환합니다.

  2. thiselement를 반환합니다.

참고: 이는 더 이상 Document자손이 아닌 요소는 더 이상 element 속성 getter에 의해 반환되지 않음을 의미합니다.

url 속성의 getter는 다음 단계를 수행해야 합니다:

  1. thisrequest가 null이면 빈 문자열을 반환합니다.

  2. urlStringthisrequest현재 URL로 둡니다.

  3. urlurlString파싱한 결과로 둡니다.

  4. url스킴이 "`data`"이면, urlString을 처음 100자로 잘라냅니다.

  5. urlString을 반환합니다.

참고: 항목에서 과도한 메모리 사용을 피하기 위해 데이터 URL의 경우 URL을 잘라냅니다.

3. 처리 모델

참고: Element Timing API를 구현하는 사용자 에이전트는 Window 컨텍스트에 대해 supportedEntryTypes"element"를 포함해야 합니다. 이를 통해 개발자는 요소 타이밍 지원 여부를 감지할 수 있습니다.

3.1. DOM 명세에 대한 수정

이 절은 [DOM] 명세가 수정되면 제거됩니다.

다음과 같이 Element 인터페이스를 확장합니다:

partial interface Element {
    [CEReactions, Reflect] attribute DOMString elementTiming;
};

3.2. 요소 타이밍 보고

Document doc, [/=paint timing info=] paintTimingInfo, pending image records순서 있는 집합 paintedImages, 및 elements순서 있는 집합 paintedTextNodes가 주어졌을 때 요소 타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
  1. paintedImages 안의 각 record에 대해:

    1. record, paintTimingInfo, 및 doc를 전달하여 이미지 요소 타이밍 보고 알고리즘을 실행합니다.

  2. paintedTextNodes 안의 각 Element element에 대해:

    1. element, paintTimingInfo, 및 doc가 주어졌을 때 텍스트 요소 타이밍 보고를 실행합니다.

3.3. 이미지 요소 타이밍 보고

pending image record record, paint timing info paintTimingInfoDocument document가 주어졌을 때 이미지 요소 타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
  1. recordelement의 "elementtiming" 콘텐츠 속성이 없으면, 이 단계를 중단합니다.

  2. intersectionRectrecordelement를 대상으로, viewport를 루트로 하여 intersection rect algorithm이 반환하는 값으로 둡니다.

  3. document관련 Realm을 사용하여 PerformanceElementTiming 객체 entry를 만들고 초기화하며, 그 paint timing infopaintTimingInfo입니다.

    1. entryrequestrecordrequest로 초기화합니다.

    2. entryelementrecordelement로 초기화합니다.

    3. entrynameDOMString "image-paint"로 초기화합니다.

    4. entryloadTimerecordloadTime으로 초기화합니다.

    5. entryintersectionRectintersectionRect로 초기화합니다.

    6. entryidentifierrecordelement의 "elementtiming" 콘텐츠 속성으로 초기화합니다.

    7. entrynaturalWidthnaturalHeightimgnaturalWidthnaturalHeight 속성 getter와 동일한 단계를 실행하여 초기화하되, 이미지로 recordrequest를 사용합니다.

    8. entryidrecordelement의 "id" 콘텐츠 속성으로 초기화합니다.

  4. entry PerformanceEntry를 큐에 넣습니다.

3.4. 텍스트 요소 타이밍 보고

Element element, paint timing info paintTimingInfoDocument document가 주어졌을 때 텍스트 요소 타이밍을 보고하라는 요청을 받으면, 다음 단계를 수행합니다:
  1. element의 "elementtiming" 콘텐츠 속성이 없으면, 이 단계를 중단합니다.

  2. intersectionRect를 빈 사각형으로 둡니다.

  3. element소유 텍스트 노드 집합 안의 각 Text node text에 대해:

    1. intersectionRecttext의 border box와 intersectionRect를 포함하는 가장 작은 사각형이 되도록 확장합니다.

  4. intersectionRect를 visual viewport와 교차시킵니다.

  5. document관련 Realm을 사용하여 PerformanceElementTiming 객체 entry를 만들고 초기화하며, 그 paint timing infopaintTimingInfo입니다.

    1. entryelementelement로 초기화합니다.

    2. entrynameDOMString "text-paint"로 초기화합니다.

    3. entryloadTime을 0으로 초기화합니다.

    4. entryintersectionRectintersectionRect로 초기화합니다.

    5. entryidentifierelement의 "elementtiming" 콘텐츠 속성으로 초기화합니다.

    6. entrynaturalWidthnaturalHeight를 0으로 초기화합니다.

    7. entryidelement의 "id" 콘텐츠 속성으로 초기화합니다.

  6. entry PerformanceEntry를 큐에 넣습니다.

4. 보안 및 개인정보 보호 고려사항

이 API는 교차 출처 이미지에 대한 일부 정보를 노출합니다. 특히 이미지의 리소스 로드 시간이 노출되며, 이는 개인정보 보호 우려의 원천이 될 수 있습니다.

그러나 ResourceTiming API가 이미 유사한 타임스탬프를 노출하므로, 이는 웹 플랫폼에 새로운 공격을 추가하지 않는 것으로 간주됩니다. 또한 onload 핸들러는 사용할 수 있을 때 로드 타이밍을 노출하며, 리소스 로드 시간은 이에 가까운 대리값입니다. onload 핸들러의 시작 시점에 계산된 현재 고해상도 시간은 이미지 로드 시간을 제공할 것입니다. loadTime은 onload 핸들러 없이도 매우 쉽게 얻을 수 있으므로 이를 노출하기로 선택했습니다. 또한 이미지 onload 핸들러나 ResourceTiming이 제공하는 누출을 제거하기 위한 수정은 이 API가 제공하는 누출도 수정할 수 있다고 생각합니다.

renderTime (표시 타임스탬프)는 실제로 새로 노출되는 정보입니다. 구현은 교차 출처 이미지 간 디코딩 시간 차이를 노출하지 않도록, 이 타임스탬프를 적어도 4밀리초 해상도로 더 거칠게 만들 것을 권고받습니다. `Timing-Allow-Origin` 같은 다른 검사는 동일 출처 이미지와 교차 출처 이미지가 동시에 렌더링되므로 여기서는 동작하지 않는다는 점에 유의하십시오. 어쨌든 거친 renderTime을 노출하는 것은 실질적인 공격 벡터가 아닙니다. 이미지 자연 크기 및 로딩 시간이 다른 방식으로 노출되기 때문입니다.

// 공격자 프레임 안.
<iframe src=attack.html></iframe>
<script>
    window.onmessage = e => {
        let timestamp = e.data;
        // 'victim.jpg'의 표시 타임스탬프를 획득했습니다!
    }
</script>

// attack.html iframe 안.
<img src='victim.jpg'/>
<script>
    // onload까지 또는 PaintTiming 항목이 보일 어떤 시점까지 기다립니다.
    onload() => {
        let entry = performance.getEntriesByType('paint')[0];
        top.postMessage(entry.startTime, '*');
    }
</script>

여기서 노출되는 또 다른 중요 매개변수는 intersectionRect입니다. 이는 예를 들어 IntersectionObserver를 사용하여 이미 폴리필할 수 있습니다. 폴리필 과정도 유사합니다. 대상 이미지 또는 텍스트 콘텐츠의 onload 핸들러에서 IntersectionObserver를 추가합니다. 이 해결책은 콘텐츠가 로드된 뒤 관찰자를 등록해야 하므로 비효율적이지만, 여전히 같은 수준의 정확도를 제공해야 합니다. 이미지가 완전히 표시될 때까지만 rect를 계산한다면, 그 시점 이후에야 항목을 노출할 수 있게 됩니다.

이미지의 렌더링 타임스탬프를 노출하고 싶지 않다면, 항목을 PerformanceObserver로 즉시 디스패치하는 것이 바람직합니다. 기다렸다가 요소 타이밍 보고 알고리즘 중에 모든 항목을 노출한다고 가정해 보겠습니다. 공격자는 이미지의 렌더링 타임스탬프에 대한 중요 정보를 추론할 수 있습니다. 이는 해당 이미지의 타이밍만 관찰함으로써 이루어질 수 있습니다. 수신한 PerformanceElementTiming 항목의 멤버로 타임스탬프가 노출되지 않더라도, 다음 렌더링 업데이트 단계까지 기다린다는 사실은, 공격자가 항목을 받은 시간을 측정하여 매우 느린 렌더링 시간과 매우 빠른 렌더링 시간을 구별할 수 있음을 의미합니다. 이는 의도치 않게 이미지의 표시 타이밍 일부를 누출할 수 있습니다.

적합성

문서 규칙

적합성 요구사항은 설명적 단언과 RFC 2119 용어의 조합으로 표현됩니다. 이 문서의 규범적 부분에서 핵심 단어 “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, 및 “OPTIONAL”은 RFC 2119에 설명된 대로 해석해야 합니다. 그러나 가독성을 위해, 이 명세에서는 이 단어들이 모두 대문자로 표시되지는 않습니다.

명시적으로 비규범으로 표시된 절, 예제 및 참고를 제외하고 이 명세의 모든 텍스트는 규범적입니다. [RFC2119]

이 명세의 예제는 “예를 들어”라는 말로 도입되거나 규범 텍스트와 구분되도록 class="example"으로 표시됩니다. 다음과 같습니다:

이는 정보 제공 예제의 예입니다.

정보 제공 참고는 “참고”라는 말로 시작하며 규범 텍스트와 구분되도록 class="note"로 표시됩니다. 다음과 같습니다:

참고, 이는 정보 제공 참고입니다.

적합 알고리즘

알고리즘의 일부로 명령형으로 표현된 요구사항 (예: "모든 선행 공백 문자를 제거한다" 또는 "false를 반환하고 이 단계를 중단한다")은 알고리즘을 도입할 때 사용된 핵심 단어 ("must", "should", "may" 등)의 의미로 해석해야 합니다.

알고리즘 또는 특정 단계로 표현된 적합성 요구사항은 최종 결과가 동등하기만 하면 어떤 방식으로든 구현할 수 있습니다. 특히 이 명세에서 정의된 알고리즘은 이해하기 쉽게 의도된 것이며 성능을 의도한 것은 아닙니다. 구현자는 최적화할 것을 권장합니다.

색인

이 명세에서 정의하는 용어

참조로 정의되는 용어

참고문헌

규범적 참고문헌

[CSS-IMAGES-3]
Tab Atkins Jr.; Elika Etemad; Lea Verou. CSS Images Module Level 3. URL: https://drafts.csswg.org/css-images-3/
[DOM]
Anne van Kesteren. DOM Standard. Living Standard. URL: https://dom.spec.whatwg.org/
[GEOMETRY-1]
Sebastian Zartner; Yehonatan Daniv. Geometry Interfaces Module Level 1. URL: https://drafts.csswg.org/geometry/
[HR-TIME-3]
Yoav Weiss. High Resolution Time. URL: https://w3c.github.io/hr-time/
[HTML]
Anne van Kesteren; et al. HTML Standard. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. Living Standard. URL: https://infra.spec.whatwg.org/
[INTERSECTION-OBSERVER]
Stefan Zager; Emilio Cobos Álvarez; Traian Captan. Intersection Observer. URL: https://w3c.github.io/IntersectionObserver/
[PAINT-TIMING]
Ian Clelland; Noam Rosenthal. Paint Timing. URL: https://w3c.github.io/paint-timing/
[PERFORMANCE-TIMELINE]
Nicolas Pena Moreno. Performance Timeline. URL: https://w3c.github.io/performance-timeline/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997년 3월. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[URL]
Anne van Kesteren. URL Standard. Living Standard. URL: https://url.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. Living Standard. URL: https://webidl.spec.whatwg.org/

IDL 색인

[Exposed=Window]
interface PerformanceElementTiming : PerformanceEntry {
    readonly attribute DOMHighResTimeStamp renderTime;
    readonly attribute DOMHighResTimeStamp loadTime;
    readonly attribute DOMRectReadOnly intersectionRect;
    readonly attribute DOMString identifier;
    readonly attribute unsigned long naturalWidth;
    readonly attribute unsigned long naturalHeight;
    readonly attribute DOMString id;
    readonly attribute Element? element;
    readonly attribute USVString url;
    [Default] object toJSON();
};

PerformanceElementTiming includes PaintTimingMixin;

partial interface Element {
    [CEReactions, Reflect] attribute DOMString elementTiming;
};

MDN

Element/elementTiming

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/element

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/id

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/identifier

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/intersectionRect

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/loadTime

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/naturalHeight

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/naturalWidth

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/renderTime

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/toJSON

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming/url

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

PerformanceElementTiming

In only one current engine.

FirefoxNoneSafariNoneChrome77+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?