1. 引言
本节为非规范性内容。 LargestContentfulPaint API 使开发者能够了解网页的加载和渲染过程,从而优化此过程。
开发者需要一个能够与用户视觉渲染体验相关联的可靠指标。像 First Paint 和 First Contentful Paint 这样的绘制加载指标侧重于初始渲染,但没有考虑被绘制内容的重要性,因此可能指示用户仍然认为页面无用的时间。
最大内容绘制(LCP)旨在成为一个页面加载指标:
-
比 First Paint 和 First Contentful Paint 更能反映用户体验
-
易于理解和推理
-
减少作弊的可能性
页面加载过程中最大的绘制通常代表了用户视角下的一个重要事件,因此我们希望默认向开发者公开该事件,使性能团队、分析提供商和实验室测量工具能够收集这些指标,无需内容创建者额外标注。
该 API 依赖于 [PAINT-TIMING] 中定义的概念,可以视为该高级特性构建在其之上的低级原语。对于内容创建者愿意标注其内容并指明页面加载周期重要节点的情况,[ELEMENT-TIMING] API 能为其提供更多可控性。
注意:Largest Contentful Paint API 只会公开符合计时条件的元素。与 Element Timing 不同,无需对元素进行标注即可让其参与 Largest Contentful Paint 的评测。
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 基于启发式方法。因此,它容易出错。它存在以下问题:
-
该算法在检测到某些类型的用户输入时会停止运行。然而,这意味着如果用户输入发生在主要内容显示之前,算法将无法捕捉到主要内容。事实上,如果用户输入发生得非常早,算法可能会产生无意义的结果,甚至没有结果。
-
为了考虑图片轮播,即使内容被移除,该内容仍被视为最大。这对使用大型内容作为占位符的启动页面会带来问题。
LargestContentfulPaint API 以文档加载为基础。因此,它不会在以下情况下重置:
-
后退-前进缓存(bfcache)的恢复操作。
-
在富 JavaScript 应用中使用的同一文档历史导航。
在使用 LargestContentfulPaint API 时,你可能需要考虑如何在该 API 之外处理这些情况,因为用户可能认为这些也是页面加载。
此外,最初在屏幕外加载的页面,例如在后台标签中,或通过预渲染技术加载的页面,将报告比预期更大的值,因为它们测量的是从加载到绘制的时间,因此也需要考虑如何处理。
2. 术语
最大内容绘制候选项是一个包含以下成员的 结构体:
3. 最大内容绘制
最大内容绘制涉及以下新接口:
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
的值。
duration
属性的 getter 必须返回 0。
renderTime
属性必须返回在 默认绘制时间戳下 this 的 绘制计时信息(paint
timing info)。
loadTime
属性必须返回 this 的 loadTime。
element
属性的 getter 必须执行以下步骤:
注:以上算法规定,已经不再是 Document
后代的元素不会再被 element
属性 getter 返回(包括 shadow DOM 内的节点)。
本规范还扩展了 Document,
为其添加了 最大内容绘制尺寸(largest contentful paint size)概念,初始值为 0。
4. 处理模型
每个Window
具备已触发滚动事件,布尔值,初始为 false。
4.1. 对 DOM 规范的修改
本节将在 [DOM] 规范完成修改后移除。
在第1步之后添加如下步骤:
4.2. 报告最大内容绘制
Document
document、 绘制时序信息 paintTimingInfo、一个 有序集合 的 待处理图片记录 paintedImages,以及一个 有序集合 的 元素 paintedTextNodes时,执行以下步骤:
注意: paintedImages 中每个待处理图片记录和 paintedTextNodes 中的文本元素,只会被 标记绘制时序 报告一次,且仅在该元素首次被认为可绘制(即具有透明度和可见性)且可内容化(即图片资源或阻塞字体已充分加载)的绘制时进行。
-
令 window 为 document 的 相关全局对象。
-
令 newCandidateSize 为 document 的 最大内容绘制尺寸。
-
令 newCandidate 为 null。
-
遍历 paintedImages 中的每个 record:
-
令 imageElement 为 record 的 元素。
-
如果 imageElement 在 document 下不 暴露用于绘制时序,则继续。
-
令 intersectionRect 为交集区域算法以 imageElement 为目标、视口为根返回的值。
-
令 size 为 有效视觉尺寸,以 intersectionRect 和 record 的 请求 为参数,针对 imageElement 计算。
-
如果 size 小于或等于 newCandidateSize,则继续。
-
将 newCandidateSize 设置为 size。
-
将 newCandidate 设置为新的 最大内容绘制候选项, 其 元素 为 imageElement, 尺寸 为 size, 请求 为 record 的 请求, 加载时间 为 record 的 加载时间。
-
-
遍历 paintedTextNodes 中的每个 textNode,
-
如果 textNode 在 document 下不 暴露用于绘制时序,则继续。
-
如果 textNode 的 alpha通道 值 <=0 或 透明度 值 <=0:
-
若 textNode 的 text-shadow 值为 none, 且 textNode 的 stroke-color 值为 透明,并且 textNode 的 stroke-image 值为 none,则继续。
-
-
令 size 为 textNode 的 有效视觉尺寸,参数为 intersectionRect 和 null。
-
如果 size 小于或等于 newCandidateSize,则继续。
-
将 newCandidateSize 设置为 size。
-
将 newCandidate 设置为新的 最大内容绘制候选项, 其 元素 为 textNode, 尺寸 为 size, 请求 为 null, 加载时间 为 0。
-
-
如果 newCandidate 不为 null:
-
创建 LargestContentfulPaint 条目,参数为 newCandidate、 paintTimingInfo 和 document。
-
4.3. 确定元素的有效视觉尺寸
为了确定一个 有效视觉尺寸,针对 元素, 执行以下步骤:
- 输入
-
intersectionRect,一个
DOMRectReadOnlyimageRequest,一个
Request或 nullelement,一个 Element
document,一个 Document
- 输出
-
要用于 Largest Contentful Paint 报告的像素数,或者如果该元素不应作为 LCP 候选,则为 null。
-
令 width 为 intersectionRect 的
width。 -
令 height 为 intersectionRect 的
height。 -
令 size 为
width。* height -
令 rootWidth 为 root 的 可视视口的宽度(不包括滚动条)。
-
令 rootHeight 为 root 的 可视视口的高度(不包括滚动条)。
-
如果 size 等于 rootWidth 乘以 rootHeight,则返回 null。
-
如果 imageRequest 不为 null,按以下步骤调整图片的位置和缩放:
-
如果 imageRequest 的 response 的内容字节数小于 size * 0.004,则返回 null。
注:该启发式方法用于判断图片资源是否包含足够多的数据以被用户视为内容。它比较传输文件的大小与实际解码和缩放后产生的像素数。极少字节编码大量像素的图片通常是低内容背景或渐变等,这类不会作为 LCP 候选。
-
令 concreteDimensions 为 imageRequest 的 具体对象尺寸(在 element 内)。
-
令 visibleDimensions 为 concreteDimensions,基于 object-position 或 background-position 及 element 的 内容框 进行位置调整。
注:这些算法在 CSS 规范中并未严格定义。预期结果是获得 element 中图片的实际位置和大小,并表示为
DOMRectReadOnly。 -
令 clientContentRect 为包含 visibleDimensions 并应用 element 变换 的最小
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 条目
为了 创建
LargestContentfulPaint
条目,用户代理必须执行如下步骤:
- 输入
-
candidate,一个 最大内容绘制候选项
paintTimingInfo,一个 绘制时序信息
document,一个
文档 - 输出
-
无
-
令 url 为空字符串。
-
如果 candidate 的 请求 不为 null, 则将 url 设置为 candidate 的 请求 的 请求 URL。
-
令 entry 为新的
LargestContentfulPaint条目,使用 document 的 相关领域,其 绘制时序信息 为 paintTimingInfo,如下设置: -
队列 PerformanceEntry entry。
5. 安全与隐私注意事项
该API底层依赖Paint Timing。与类似的Element Timing API不同,若某些元素尺寸尽管较小但在当前为“最大”,LCP仍可能暴露其计时细节。但这不会泄露比Element Timing已暴露更多的敏感信息。