元素计时 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 流程 文档约束。

1. 引言

本节为非规范性内容。

知道关键元素何时显示在屏幕上,是理解页面加载性能的关键。 虽然快速渲染基本组件不足以带来令人满意的加载体验,但它是必要的。 因此,监测这些渲染时间戳对于改进页面加载并防止回退非常重要。

本规范为开发者和分析服务提供者提供了一种 API,用于测量关键元素的渲染时间戳。 目前还没有很好的方法可以为真实用户测量这些时间戳。 现有方法要么需要过早注册观察器,要么需要大量 DOM 操作。 这些方法会在 § 4 安全与隐私考量 一节中讨论。

Web 开发者是其站点中关键用户交互方面的专家,因此应允许他们 告知用户代理自己关心哪些元素。 因此,此 API 暴露关于 Web 开发者所标注元素的渲染计时信息。

1.1. 暴露的元素

Element Timing API 支持关于 符合计时条件的 元素的计时信息,如 [PAINT-TIMING] 所定义。

具有 "elementtiming" 内容属性的元素,会在 报告 图像元素计时报告文本元素计时 算法中被报告。

1.2. 用法示例

以下示例展示了一个通过其 elementtiming 属性注册以供观察的图像,以及一个收集计时信息的观察器。

<img... elementtiming='foobar'/>
<p elementtiming='important-paragraph'>This is text I care about.</p>
...
<script>
const observer = new PerformanceObserver((list) => {
  let perfEntries = list.getEntries();
  // 通过迭代处理这些条目。
});
observer.observe({type: 'element', buffered: true});
</script>

以下是一些示例元素,它们的渲染时间戳可以使用此 API 进行测量,并且 应与页面导航进行比较:

通过将渲染时间戳与输入时间戳进行比较,该 API 还可以用于页面加载之外的用例。 例如,开发者可以监测在触发某个 widget 的点击之后,该 widget 显示出来所需的时间。

2. Element Timing

Element Timing 涉及以下新接口:

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 步骤是:在给定 this绘制计时信息的情况下,返回默认绘制时间戳

loadTime 属性的 getter 必须返回它被初始化为的值。

intersectionRect 属性必须返回它被初始化为的值。

identifier 属性的 getter 必须返回它被初始化为的值。

naturalWidth 属性必须返回它被初始化为的值。

naturalHeight 属性必须返回它被初始化为的值。

id 属性的 getter 必须返回它被初始化为的值。

element 属性的 getter 必须执行以下步骤:

  1. 如果 this元素在给定 null 时未为绘制计时而暴露,则返回 null。

  2. 返回 this元素

注: 这意味着一个不再是 Document后代的元素,将不再由 element 属性 getter 返回。

url 属性的 getter 必须执行以下步骤:

  1. 如果 this请求为 null,则返回空字符串。

  2. urlStringthis请求当前 URL

  3. url解析 urlString 的结果。

  4. 如果 url方案为 "`data`",则将 urlString 截断为其前 100 个字符。

  5. 返回 urlString

注: 对于 data URL,URL 会被截断,以避免 条目中占用过多内存。

3. 处理模型

注: 实现 Element Timing API 的用户代理 需要在 Window 上下文的 supportedEntryTypes 中包含 "element"。 这允许开发者检测对 element timing 的支持。

3.1. 对 DOM 规范的修改

一旦 [DOM] 规范被修改,本节将被移除。

我们按如下方式扩展 Element 接口:

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

3.2. 报告元素计时

当被要求在给定 Document doc、[/=paint timing info=] paintTimingInfo、一个由待处理图像记录组成的有序集合 paintedImages,以及一个由元素 组成的有序 集合 paintedTextNodes 的情况下报告 元素计时时,执行以下步骤:
  1. paintedImages 中的每个 record

    1. 运行报告图像元素计时算法, 传入 recordpaintTimingInfodoc

  2. paintedTextNodes 中的每个 Element element

    1. 在给定 elementpaintTimingInfodoc 的情况下,运行报告文本元素计时

3.3. 报告图像元素计时

当被要求在给定一个 待处理图像记录 record、一个 绘制计时 信息 paintTimingInfo 和一个 Document document 的情况下报告图像元素计时时,执行以下步骤:
  1. 如果 record元素的 "elementtiming" 内容属性不存在,则中止这些步骤。

  2. intersectionRect 为使用 record元素作为目标、viewport 作为根运行交叉矩形算法所返回的值。

  3. 使用 document相关 Realm,创建并初始化一个 PerformanceElementTiming 对象 entry,其绘制计时信息paintTimingInfo

    1. entry请求初始化为 record请求

    2. entry元素初始化为 record元素

    3. entryname 初始化为 DOMString "image-paint"。

    4. entryloadTime 初始化为 recordloadTime

    5. entryintersectionRect 初始化为 intersectionRect

    6. entryidentifier 初始化为 record元素的 "elementtiming" 内容属性。

    7. 通过为一个 imgnaturalWidthnaturalHeight 属性 getter 运行相同步骤,但使用 record请求作为图像, 来初始化 entrynaturalWidthnaturalHeight

    8. entryid 初始化为 record元素的 "id" 内容属性。

  4. 将 PerformanceEntry 入队 entry

3.4. 报告文本元素计时

当被要求在给定一个 Element element、一个 绘制计时信息 paintTimingInfo 和一个 Document document 的情况下报告文本元素计时时,执行以下步骤:
  1. 如果 element 的 "elementtiming" 内容属性 不存在,则中止这些步骤。

  2. intersectionRect 为空矩形。

  3. element拥有的文本节点集合中的每个 Text 节点 text

    1. 增广 intersectionRect,使其成为包含 text 的 border box 和 intersectionRect 的最小矩形。

  4. intersectionRect 与 visual viewport 相交。

  5. 使用 document相关 Realm,创建并初始化一个 PerformanceElementTiming 对象 entry,其绘制计时信息paintTimingInfo

    1. entry元素初始化为 element

    2. entryname 初始化为 DOMString "text-paint"。

    3. entryloadTime 初始化为 0。

    4. entryintersectionRect 初始化为 intersectionRect

    5. entryidentifier 初始化为 element 的 "elementtiming" 内容 属性。

    6. entrynaturalWidthnaturalHeight 初始化为 0。

    7. entryid 初始化为 element 的 "id" 内容属性。

  6. 将 PerformanceEntry 入队 entry

4. 安全与隐私考量

此 API 暴露了一些关于跨源图像的信息。 特别是,图像会暴露其资源加载时间,这可能成为隐私方面的担忧来源。

然而,这被认为不会向 Web 平台添加新的攻击,因为 ResourceTiming API 已经暴露了 类似的时间戳。 此外,onload 处理器会在可用时暴露加载计时,而资源加载时间与此非常接近。 在 onload 处理器开始时计算的当前高精度时间会提供图像加载时间。 我们选择暴露 loadTime, 因为即使没有 onload 处理器,也很容易获取它。 此外,我们相信,任何用于移除图像 onload 处理器或 ResourceTiming 所提供泄露的修复, 也可以修复此 API 所提供的泄露。

renderTime (显示时间戳)确实是新暴露的信息。建议实现进一步粗化该时间戳, 至少粗化到 4 毫秒分辨率,以避免暴露跨源图像之间解码时间的差异。注意,其他检查 例如 `Timing-Allow-Origin` 在这里不起作用,因为同源图像和跨源图像会同时被渲染。 无论如何,暴露粗粒度的 renderTime 并不是一个实质性的攻击向量,因为图像自然尺寸 和加载时间已经通过其他方式暴露。

// 在攻击者 frame 中。
<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。 这已经可以 polyfill,例如使用 IntersectionObserver。 polyfill 过程会类似:在目标图像或文本内容的 onload 处理器上添加一个 IntersectionObserver。 该方案效率低,因为它需要在内容加载后注册观察器,但仍应提供相同程度的准确性。 如果我们只计算到图像完全显示为止的 rect,那么也只能在那个时间之后暴露 条目。

如果我们不想暴露图像的渲染时间戳,最好立即将条目分发给 PerformanceObserver。 假设我们等待并在报告元素计时算法期间暴露所有条目。 攻击者就可以推断关于图像渲染时间戳的非平凡信息。 它会通过仅观察该图像的计时来做到这一点。 即使时间戳没有作为收到的 PerformanceElementTiming 条目的成员暴露, 我们等待到下一个更新渲染步骤这一事实,意味着攻击者可以通过测量收到 条目的时间来区分非常慢的渲染时间和非常快的渲染时间。 这会无意中泄露图像的一些显示计时。

一致性

文档 约定

一致性要求通过描述性断言 和 RFC 2119 术语的组合来表达。 规范性部分中的关键词 “MUST”、“MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、“RECOMMENDED”、 “MAY” 和 “OPTIONAL” 应按 RFC 2119 中所述进行解释。 但是,为了可读性, 这些词在本规范中并不全部以大写字母出现。

本规范的所有文本均为规范性内容, 但明确标记为非规范性的章节、示例和注释除外。 [RFC2119]

本规范中的示例会以 “for example” 一词引入, 或通过 class="example" 与规范性文本分隔开来, 如下所示:

这是一个信息性示例的例子。

信息性注释以 “Note” 一词开头, 并通过 class="note" 与规范性文本分隔开来, 如下所示:

注:这是一个信息性注释。

一致性 算法

作为算法一部分以祈使语气表述的要求 (例如 "strip any leading space characters" 或 "return false and abort these steps") 应按引入该算法时所使用的关键词 ("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?