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. 术语
最大内容绘制候选项是一个包含以下成员的 结构体:
注:可以弱引用方式存储最大内容绘制候选项的元素,以防止泄漏已从 DOM 中移除的元素。
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
:
-
一个当前最大内容绘制候选项,其值为最大内容绘制候选项或 null, 初始值为 null。
4. 处理模型
每个Window
具备已触发滚动事件,布尔值,初始为 false。
4.1. 对 DOM 规范的修改
本节将在 [DOM] 规范完成修改后移除。
在第1步之后添加如下步骤:
4.2. 报告最大内容绘制
Document
document、一个绘制时序信息 paintTimingInfo、一个由待处理图像记录组成的有序集合
paintedImages,以及一个由元素组成的有序集合
paintedTextNodes的情况下,报告最大内容绘制时,执行以下步骤:
注: paintedImages中的每个待处理图像记录以及 paintedTextNodes中的每个文本元素, 都只会从标记绘制时序中报告恰好一次,报告发生在元素首次被视为可绘制 (即具有不透明度和可见性)且具有内容(即图像资源或阻塞字体已充分加载)的绘制中。
-
令 window 为 document的相关全局对象。
-
令 newCandidate 为在给定 document、paintedImages、 paintedTextNodes以及 document的当前最大内容绘制候选项的情况下,计算新的最大内容绘制候选项的结果。
-
如果 newCandidate 为 null,则返回。
-
将 document的当前最大内容绘制候选项设置为 newCandidate。
-
令 entry 为使用 newCandidate、paintTimingInfo和 document创建 LargestContentfulPaint 条目的结果。
-
将 PerformanceEntry entry入队。
Document
document、一个由待处理图像记录组成的有序集合
paintedImages、一个由元素组成的有序集合
paintedTextNodes,以及一个最大内容绘制候选项或
null currentCandidate的情况下,计算新的最大内容绘制候选项,执行以下步骤。这些步骤
返回一个最大内容绘制候选项或 null。
-
如果 currentCandidate 不为 null,则令 currentSize 为 currentCandidate的尺寸;否则为 0。
-
令 largestSize 为 currentSize。
-
令 newCandidate 为 null。
-
对于 paintedImages中的每个 record:
-
令 imageElement 为 record的元素。
-
如果在给定 document的情况下,imageElement未暴露给绘制时序,则继续。
-
令 intersectionRect 为以 imageElement作为目标、以视口作为根 运行交集矩形算法所返回的值。
-
令 result 为在给定 intersectionRect和 record的请求的情况下, imageElement的有效视觉尺寸。
-
如果 result 为 null,则继续。
-
如果 result的尺寸小于或等于 largestSize,则继续。
-
将 largestSize设置为 result的尺寸。
-
将 newCandidate设置为一个新的最大内容绘制候选项,其值如下:
-
-
对于 paintedTextNodes中的每个 textNode,
-
如果在给定 document的情况下,textNode未暴露给绘制时序,则继续。
-
如果 textNode的alpha 通道值 <=0,或不透明度 值 <=0:
-
如果 textNode的text-shadow值为 none, textNode的stroke-color值为transparent,并且 textNode的stroke-image值为 none,则继续。
-
-
令 intersectionRect 为 textNode的所拥有文本节点集合中所有
Text节点的边框框并集与可视视口相交所得的结果。 -
令 result 为在给定 intersectionRect和 null 的情况下, textNode的有效视觉尺寸。
-
如果 result 为 null,则继续。
-
如果 result的尺寸小于或等于 largestSize,则继续。
-
将 largestSize设置为 result的尺寸。
-
将 newCandidate设置为一个新的最大内容绘制候选项,其值如下:
-
-
如果 newCandidate不为 null 且 currentSize大于 0:
-
返回 newCandidate。
4.3. 确定元素的有效视觉尺寸
为了确定一个元素的有效视觉尺寸,运行以下步骤:
- 输入
-
intersectionRect,一个
DOMRectReadOnlyimageRequest,一个
Request或 nullelement,一个元素
document,一个文档
- 输出
-
一个有效视觉尺寸结果,它是一个结构体,包含尺寸(一个数值)、宽度(一个数值)以及高度(一个数值),表示要为最大内容绘制报告的有效视觉尺寸、宽度和高度, 单位为像素;如果该元素不应作为 LCP 候选项,则为 null。
-
令 width 为 intersectionRect的
width, 向上舍入到最接近的整数。 -
令 height 为 intersectionRect的
height, 向上舍入到最接近的整数。 -
令 size 为
width。* height -
令 rootWidth 为 root的可视视口的宽度,不包括任何滚动条。
-
令 rootHeight 为 root的可视视口的高度,不包括任何 滚动条。
-
如果 size 等于 rootWidth 乘以 rootHeight,则返回 null。
-
如果 imageRequest 不为 null,则运行以下步骤以针对图像 定位和放大进行调整:
-
如果 imageRequest的响应的内容长度(以字节为单位)小于 size * 0.004,则返回 null。
注:此启发式方法用于测试 图像资源是否包含足够的数据,以便用户将其视为具有内容。它会将传输的文件大小 与解码并应用任何图像缩放后实际生成的像素数进行比较。使用极少字节 编码大量像素的图像通常是内容较少的背景、渐变等,因此不被 视为 LCP 候选项。
-
令 concreteDimensions 为 imageRequest在 element内的具体对象尺寸。
-
令 visibleDimensions 为 concreteDimensions,并根据 object-position或background-position以及 element的内容框针对定位进行调整。
注:其中一些 算法在 CSS 中没有严格定义。预期结果是以一个
DOMRectReadOnly获取图像在 element中的实际位置和尺寸。 -
令 clientContentRect 为包含 visibleDimensions 并应用了 element的变换的最小
DOMRectReadOnly。 -
令 intersectingClientContentRect 为 clientContentRect与 intersectionRect的交集。
-
将 width设置为 intersectingClientContentRect的
width, 向上舍入到最接近的整数。 -
将 height设置为 intersectingClientContentRect的
height, 向上舍入到最接近的整数。 -
将 size设置为
width。* height注:这可确保我们 仅与图像本身相交,而不与元素的装饰相交。
-
如果 naturalArea 为 0,则返回 null。
-
令 boundingClientArea 为
clientContentRect的。width* clientContentRect的height -
令 scaleFactor 为
boundingClientArea。/ naturalArea -
如果 scaleFactor 大于 1,则将 size除以 scaleFactor。
-
-
4.4. 创建 LargestContentfulPaint 条目
为了创建一个
LargestContentfulPaint
条目,用户代理必须运行以下步骤:
5. 安全与隐私注意事项
该API底层依赖Paint Timing。与类似的Element Timing API不同,若某些元素尺寸尽管较小但在当前为“最大”,LCP仍可能暴露其计时细节。但这不会泄露比Element Timing已暴露更多的敏感信息。