长期以来,对于 Web 开发者而言,衡量网页主要内容的加载速度和对用户可见一直是一个挑战。
load 或 DOMContentLoaded 等旧指标并不理想,因为它们不一定与用户在屏幕上看到的内容相对应。而较新的以用户为中心的性能指标(例如首次内容渲染 (FCP))只能捕获加载体验的开端。如果页面显示启动画面或显示加载指示器,这一时刻与用户就没有太大关系。
过去,我们建议采用首次有效绘制 (FMP) 和速度指数 (SI)(两者均在 Lighthouse 中提供)等性能指标,以帮助捕获初始绘制后的更多加载体验,但这些指标非常复杂、难以解释,而且往往是错误的,这意味着它们仍然无法确定页面主要内容的加载时间。
有时越简单越好。根据 W3C Web 性能工作组中的讨论和 Google 的研究,我们发现,要衡量网页主要内容的加载时间,更为准确的方法是查看最大元素的呈现时间。
什么是 LCP?
Largest Contentful Paint (LCP) 指标会报告视口内可见的最大图片或文本块的呈现时间(相对于网页首次开始加载的时间)。
LCP 得分是多少?
为了提供良好的用户体验,网站应尽力将 Largest Contentful Paint 设置为 2.5 秒或更短。为确保您的大多数用户都能达到此目标,您不妨将网页加载的第 75 百分位(按移动设备和桌面设备细分)作为衡量阈值。
会考虑哪些元素?
根据 Largest Contentful Paint API 中当前的规定,Largest Contentful Paint 考虑的元素类型包括:
<img>
元素<svg>
元素内的<image>
元素- 包含海报图片的
<video>
元素(系统会使用海报图片加载时间) - 一个元素,带有通过
url()
函数(而不是 CSS 渐变)加载的背景图片 - 包含文本节点或其他内嵌级别文本元素的子项的块级元素。
- 为自动播放
<video>
元素而绘制的第一帧(截至 2023 年 8 月) - 动画图片格式(例如 GIF 动画)的第一帧(截至 2023 年 8 月)
请注意,我们有意将元素限制在这一数量有限的集合中,目的是在一开始简化问题。随着研究的深入,未来可能会添加其他元素(例如完整的 <svg>
支持)。
除了考虑某些元素之外,系统还会应用某些启发法来排除某些可能被视为“非内容”的元素。对于基于 Chromium 的浏览器,包括:
- 不透明度为 0 且对用户不可见的元素
- 覆盖整个视口的元素,很可能被视为背景而非内容
- 占位符图片或其他低熵的图片,可能无法反映网页真实内容
浏览器可能会继续改进这些启发法,以确保匹配用户对于最大内容元素的预期。
这些“内容”启发式算法可能与 First Contentful Paint (FCP) 所使用的启发法不同,后者可能会考虑其中某些元素(例如占位符图片或完整视口图片),即使它们不符合 LCP 候选条件也是如此。尽管两者的名称都使用了“contentful”,但这些指标的目的并不相同。FCP 测量的是任何内容绘制到屏幕上的时间,以及 LCP 时间(绘制主要内容),以便 LCP 更有选择性。
如何确定元素的大小?
针对 Largest Contentful Paint 报告的元素尺寸通常是用户在视口中可见的尺寸。如果该元素延伸到视口之外,或者有任何元素被剪裁或出现不可见的overflow,这些部分都不会计入元素的大小。
对于已根据其固有尺寸调整大小的图片元素,报告的尺寸是可见尺寸或固有尺寸(以较小者为准)。例如,缩小到比其固有大小小得多的图片将只报告其显示时的大小,而拉伸或展开为更大尺寸的图片将只报告其固有大小。
对于文本元素,系统仅考虑文本节点的大小(包含所有文本节点的最小矩形)。
对于所有元素,不考虑通过 CSS 应用的任何外边距、内边距或边框。
何时报告最大 Contentful Paint?
网页通常会分阶段加载,因此网页上最大的元素可能会发生变化。
为了应对这种可能的变化,浏览器在绘制完第一帧后,会立即分派 largest-contentful-paint
类型的 PerformanceEntry
,用于标识最大的内容元素。不过,在渲染后续帧后,只要最大内容元素发生变化,该 API 就会再分派另一个 PerformanceEntry
。
例如,在包含文本和主打图片的网页上,浏览器最初可能只渲染文本 - 此时,浏览器会分派 largest-contentful-paint
条目,其 element
属性可能会引用 <p>
或 <h1>
。稍后,当主打图片完成加载时,系统会分派第二个 largest-contentful-paint
条目,并且其 element
属性会引用 <img>
。
请务必注意,元素只有在呈现并对用户可见后,才能被视为最大的内容元素。尚未加载的图片不会被视为“已渲染”。在字体块期间,使用网页字体的文本节点也不例外。在这种情况下,系统可能会将较小的元素报告为最大的内容元素,但是一旦较大的元素呈现完毕,系统就会通过另一个 PerformanceEntry
对象报告该元素。
除了延迟加载图片和字体之外,网页还可以在有新内容可用时向 DOM 添加新元素。如果其中任何新元素大于之前的最大内容元素,系统还会报告一个新的 PerformanceEntry
。
如果将当前最大内容元素的某个元素从视口中移除(甚至从 DOM 中移除),除非渲染了较大的元素,否则该元素将一直是最大内容元素。
一旦用户与页面交互(通过点按、滚动或按键),浏览器就会停止报告新条目,因为用户互动通常会改变向用户显示的内容(滚动操作时更是如此)。
出于分析目的,您应仅向分析服务报告最近分派的 PerformanceEntry
。
加载时间与呈现时间
出于安全原因,对于缺少 Timing-Allow-Origin
标头的跨源图片,系统不会公开图片的呈现时间戳。而是仅公开其加载时间(因为已通过许多其他 Web API 公开)。
这可能会导致网络 API 报告的 LCP 早于 FCP 的情况,这种情况看似不可能。之所以出现这种情况,是因为这一安全限制之所以会出现,只是因为。
我们始终建议您尽可能设置 Timing-Allow-Origin
标头,以便指标更加准确。
如何处理元素布局和尺寸更改?
为了使计算和分派新性能条目的性能开销保持在较低水平,更改元素的大小或位置不会生成新的 LCP 候选值。系统只会考虑元素的初始尺寸和在视口中的位置。
这意味着,系统可能不会报告最初呈现在屏幕外,然后在屏幕上转换的图片。这也意味着,最初在视口中呈现,但后来被下推、已不在视野范围内的元素仍会报告其初始视口内尺寸。
示例
下面列举了一些示例来说明何时会在一些热门网站上发生 Largest Contentful Paint:
在上述两个时间轴中,最大的元素会随着内容加载而变化。在第一个示例中,向 DOM 添加了新内容,这会改变最大的元素。在第二个示例中,布局会发生变化,并且之前最大的内容会从视口中移除。
延迟加载的内容通常大于网页上已有的内容,但情况不一定如此。以下两个示例展示了在网页完全加载之前发生的 Largest Contentful Paint。
在第一个示例中,Instagram 徽标相对较早地加载,即使其他内容逐步显示,该徽标也仍是最大的元素。在 Google 搜索结果页示例中,最大的元素是任何图片或徽标完成加载之前显示的一段文本。由于所有单个图片都小于此段落,因此在整个加载过程中,该图片始终是最大的元素。
如何衡量 LCP
字段工具
实验工具
使用 JavaScript 测量 LCP
如需在 JavaScript 中测量 LCP,您可以使用 Largest Contentful Paint API。以下示例展示了如何创建用于监听 largest-contentful-paint
条目并将其记录到控制台的 PerformanceObserver
。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
在上面的示例中,每个记录的 largest-contentful-paint
条目都代表当前的 LCP 候选版本。通常,发出的最后一个条目的 startTime
值是 LCP 值,但并非总是如此。并非所有 largest-contentful-paint
条目都可用于测量 LCP。
以下部分列出了 API 报告的内容和指标计算方式之间的差异。
指标与 API 之间的区别
- API 将为后台标签页中加载的页面分派
largest-contentful-paint
条目,但在计算 LCP 时应忽略这些页面。 - API 会在页面已转入后台运行时继续分派
largest-contentful-paint
条目,但在计算 LCP 时应忽略这些条目(只有当页面始终位于前台时,才应考虑相关元素)。 - 从往返缓存中恢复网页时,API 不会报告
largest-contentful-paint
条目,但在这种情况下,应衡量 LCP,因为用户将它们视为不同的网页访问。 - API 不会考虑 iframe 中的元素,但指标会考虑,因为它们是网页用户体验的一部分。在 iframe 内包含 LCP 的网页(例如嵌入式视频上的海报图片)中,CrUX 和 RUM 之间会显示差异。若要正确衡量 LCP,您应考虑使用它们。子帧可以使用 API 将其
largest-contentful-paint
条目报告给父帧以进行聚合。
开发者可以使用 web-vitals
JavaScript 库来衡量 LCP,而无需记住所有这些细微差异(如果可能,请注意,iframe 问题未涵盖在内):
import {onLCP} from 'web-vitals';
// Measure and log LCP as soon as it's available.
onLCP(console.log);
您可以参阅 onLCP()
的源代码,获取有关如何在 JavaScript 中测量 LCP 的完整示例。
如果最大的元素不是最重要的元素,该怎么办?
在某些情况下,网页上最重要的元素与最大的元素不同,开发者可能更希望衡量其他这些元素的呈现时间。这可以使用 Element Timing API 实现,如自定义指标一文中所述。
如何提高 LCP
我们提供了有关优化 LCP 的完整指南,可指导您确定现场 LCP 时间,并使用实验室数据深入分析并对其进行优化。
其他资源
- Annie Sullivan 在 performance.now() 上从 Chrome 中的性能监控中汲取的经验(2019 年)
更新日志
有时,系统会在用于衡量指标的 API 中发现 bug,有时也会在指标本身的定义中发现 bug。因此,有时必须进行更改,而且这些更改可能会在内部报告和信息中心内表现为改进或回归。
为帮助您对此进行管理,这些指标的实现或定义的所有更改都会显示在此 CHANGELOG 中。
如果您对这些指标有反馈意见,可以在 web-vitals-feedback Google 网上论坛中提供。