过去,衡量网页主要内容加载和对用户可见的速度一直是 Web 开发者面临的一项挑战。load 或 DOMContentLoaded 等较旧的指标效果不佳,因为它们与用户在屏幕上看到的内容不一定对应。以用户为中心的较新性能指标(如 First Contentful Paint (FCP))只能捕获加载体验的初始阶段。如果网页显示启动画面或加载指示器,这一时刻与用户不太相关。
过去,我们推荐过首次有效绘制 (FMP) 和速度指数 (SI)(均在 Lighthouse 中提供)等性能指标,以帮助捕获初始绘制后的更多加载体验,但这些指标复杂、难以解释且经常出错 - 这意味着它们仍然无法确定网页的主要内容何时加载完毕。
根据 W3C 网络性能工作组中的讨论和 Google 所做的研究,我们发现,如果要更准确地衡量网页主要内容的加载时间,请查看最大元素的呈现时间。
什么是 LCP?
LCP 会报告视口中可见的最大图片或文本块的呈现时间(相对于用户首次转到相应网页的时间)。
LCP 得分是多少?
为了提供良好的用户体验,网站应尽力将 Largest Contentful Paint 的时长控制在 2.5 秒或更短。为确保大多数用户都能达到此目标,建议将网页加载的第 75 个百分位作为阈值衡量,并按移动设备和桌面设备细分。
会考虑哪些元素?
目前在 Largest Contentful Paint API、元素的类型 Largest Contentful Paint 会考虑以下因素:
<img>
元素(第一帧呈现时间用于动画内容,例如 GIF 或动画 PNG)<svg>
元素内的<image>
元素<video>
元素(使用海报图片加载时间或视频的第一帧呈现时间,以两者中较早达到者为准)- 此元素包含使用
url()
函数加载的背景图片(与 CSS 渐变相反) - 包含文本节点或其他内嵌级文本元素子级的块级元素。
请注意,将元素限制到这个有限的集合是有意为之,以便一开始就简单易行。随着研究的深入,未来可能会添加其他元素(例如完全支持 <svg>
)。
LCP 衡量不仅仅考虑部分元素,还会使用启发法来排除用户可能会视为“非内容”的某些元素。对于基于 Chromium 的浏览器,包括:
- 不透明度为 0 且对用户不可见的元素
- 覆盖整个视口的元素,此类元素可能会被视为背景(而非内容)
- 占位符图片或其他具有低熵的图片,可能无法反映网页的实际内容
浏览器可能会继续改进这些启发法,确保我们能满足用户对最大的内容元素的预期。
这些“内容”启发式算法可能与 First Contentful Paint (FCP) 使用的算法不同,FCP 可能会考虑其中一些元素,例如占位图片或完整视口图片,即使它们不符合 LCP 候选条件。尽管两者都使用“contentful”但这些指标的目的有所不同。FCP 会衡量何时将任何内容绘制到屏幕上,以及 LCP 何时绘制到主内容,以便提高 LCP 的选择性。
元素大小是如何确定的?
针对 LCP 报告的元素的尺寸通常是用户在视口内可见的尺寸。如果元素延伸到视口之外,或者任何元素被截断或具有不可见的“溢出”,则这些部分不会计入元素的尺寸。
对于已根据固有尺寸调整大小的图片元素,报告的尺寸是可见尺寸或固有尺寸(以较小者为准)。
对于文本元素,LCP 仅考虑可包含所有文本节点的最小矩形。
对于所有元素,LCP 不会考虑使用 CSS 应用的外边距、内边距或边框。
何时报告 LCP?
网页通常会分阶段加载,因此,网页上最大的元素可能会发生变化。
为了应对这种可能的变更,浏览器会在绘制完第一帧后,立即分派类型为 largest-contentful-paint
的 PerformanceEntry
,用于识别最大的内容元素。但是,在渲染后续帧后,只要最大的内容元素发生变化,它就会分派另一个 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 中,这会更改最大的元素。在第二个示例中,布局发生变化,并且之前最大的内容会从视口中移除。
虽然延迟加载的内容大于网页上已有的内容,但实际情况并非如此。接下来的两个示例显示的是在网页完全加载之前发生的 LCP。
在第一个示例中,Instagram 徽标的加载相对较早,即使其他内容逐渐显示,它仍然是最大的元素。在 Google 搜索结果页示例中,最大的元素是在所有图片或徽标加载完毕之前显示的一段文字。由于所有单个图片都小于此段落,因此该段落在整个加载过程中仍然是最大的元素。
如何衡量 LCP
实地工具
实验工具
在 JavaScript 中衡量 LCP
如需在 JavaScript 中衡量 LCP,您可以使用 Largest Contentful Paint API。以下示例展示了如何创建 PerformanceObserver
来监听 largest-contentful-paint
条目并将其记录到控制台中。
new PerformanceObserver((entryList) => {
for (const entry of entryList.getEntries()) {
console.log('LCP candidate:', entry.startTime, entry);
}
}).observe({type: 'largest-contentful-paint', buffered: true});
<ph type="x-smartling-placeholder">
在上面的示例中,记录的每个 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
条目报告给父帧以进行聚合。 - API 从导航开始开始测量 LCP,但对于预渲染的网页,LCP 应从
activationStart
开始测量,因为这与用户所体验到的 LCP 时间相对应。
开发者不必记住所有这些细微差异,而是可以使用 web-vitals
JavaScript 库来衡量 LCP,由其为您处理这些差异(如果可能,请注意 iframe 问题并未涵盖在内):
import {onLCP} from 'web-vitals';
// Measure and log LCP as soon as it's available.
onLCP(console.log);
如需查看有关如何在 JavaScript 中衡量 LCP 的完整示例,请参阅 onLCP()
的源代码。
如果最大的元素不是最重要怎么办?
在某些情况下,网页上最重要的元素(或多个元素)并不同于最大元素,因此开发者可能更关注于衡量这些其他元素的呈现时间。这可通过使用 Element Timing API 来实现,如自定义指标一文中所述。
如何改进 LCP
我们提供了有关优化 LCP 的完整指南,可引导您完成在现场识别 LCP 时间并使用实验室数据进行深入分析和优化的流程。
其他资源
- Annie Sullivan 从 Chrome 中监控性能的经验教训,作者:performance.now()(2019 年)
更新日志
有时,错误是在用于衡量指标的 API 中发现的,有时是在指标本身的定义中发现的。因此,有时必须进行更改,这些更改可能会在内部报告和信息中心显示为改进或回归。
为帮助您应对此问题,对这些指标的实现或定义所做的所有更改都会显示在此更新日志中。
如果您对这些指标有反馈意见,可以在 web-vitals-feedback Google 群组中提供。