Largest Contentful Paint (LCP) 是一种稳定的 Core Web Vitals 指标,用于衡量感知的加载速度。 它用于标记网页加载时间轴中可能加载了网页主要内容的时间点。快速 LCP 有助于让用户确信相应网页有用。
一直以来,Web 开发者衡量网页主要内容的加载速度以及用户可以看到的速度一直都是一个挑战。load 或 DOMContentLoaded 等旧指标效果欠佳,因为它们不一定与用户在屏幕上看到的内容一致。而较新的以用户为中心的性能指标(如首次内容绘制 (FCP))仅捕获加载体验的开始阶段。如果页面显示启动画面或显示加载指示器,则说明这一时刻与用户没有太大关系。
过去,我们已推荐采用首次有效渲染时间 (FMP) 和速度指数 (SI)(两者均在 Lighthouse 中提供)等性能指标来帮助捕获初始绘制后的更多加载体验,但这些指标比较复杂,难以解释,而且通常错误,这意味着它们仍然无法确定页面的主要内容的加载时间。
根据 W3C Web 性能工作组中的讨论和 Google 的研究,我们发现,衡量页面主要内容的加载时间的更准确方法是查看最大元素的呈现时间。
什么是 LCP?
LCP 报告的是视口中可见最大图片或文本块的呈现时间(相对于用户首次导航到相应网页的时间)。
良好的 LCP 得分是多少?
为了提供良好的用户体验,网站应努力将 LCP 控制在 2.5 秒以内。为确保您的大多数用户都达到此目标,最好衡量一下网页加载的第 75 个百分位(按移动设备和桌面设备细分)。
需要考虑哪些元素?
如 Largest Contentful Paint API 中所述,Largest Contentful Paint 考虑的元素类型包括:
<img>
元素(第一帧呈现时间用于 GIF 或动画 PNG 等动画内容)<svg>
元素内的<image>
元素<video>
元素(系统会使用视频的海报图片加载时间或第一帧显示时间,以较早者为准)- 一个元素,带有使用
url()
函数(而不是 CSS 渐变)加载的背景图片 - 包含文本节点或其他内嵌级文本元素子元素的块级元素。
将元素限制为这个有限的集合是有意降低复杂性的。随着开展更多研究,未来可能会添加其他元素(例如完整的 <svg>
支持)。
除了仅考虑部分元素之外,LCP 衡量功能还会使用启发法来排除用户可能会认为“无内容”的特定元素。对于基于 Chromium 的浏览器,其中包括:
- 不透明度为 0 的元素对用户不可见。
- 覆盖整个视口的元素,它们可能是背景元素。
- 占位符图片或其他低熵图片,可能无法反映网页的真实内容。
浏览器可能会继续改进这些启发词语,以确保达到用户对最大内容元素的预期。
这些“内容性”启发式算法与 FCP 采用的启发法不同,FCP 可能会考虑其中某些元素(例如占位符图片或完整的视口图片),即使它们不符合 LCP 候选条件也是如此。尽管两者的名称中都使用“contentful”,但这两个指标的目的不同。FCP 衡量的是任何内容何时绘制到屏幕上,而 LCP 测量何时绘制主要内容。
如何确定元素的大小?
针对 LCP 报告的元素尺寸通常是用户在视口内可见的尺寸。如果该元素超出视口,或者有任何元素被剪裁或存在不可见的overflow,这些部分便不会计入该元素的尺寸。
对于根据固有尺寸调整过大小的图片元素,报告的尺寸为可见尺寸或固有尺寸(以较小者为准)。
对于文本元素,LCP 仅考虑可以包含所有文本节点的最小矩形。
对于所有元素,LCP 不会考虑使用 CSS 应用的外边距、内边距或边框。
何时报告 LCP?
网页通常会分阶段加载,因此,页面上最大的元素可能会在加载期间发生变化。
为了应对这种可能的变化,浏览器在绘制完第一帧后,会立即分派 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
标头的跨源图片,系统不会公开图片的渲染时间戳。而是只能使用其他 API 已经公开的加载时间。
这可能会导致一种看似不可能的情况,即 Web API 报告的 LCP 早于 FCP。这只是因为存在这种安全限制,并不代表实际发生的情况。
我们始终建议您尽可能设置 Timing-Allow-Origin
标头,以提高指标的准确性。
如何处理元素布局和尺寸更改?
为了降低计算和调度新性能条目的性能开销,更改元素的大小或位置不会生成新的 LCP 候选内容。系统只会考虑元素的初始尺寸和在视口中的位置。
这意味着,系统可能不会报告最初呈现在屏幕之外、然后在屏幕上进行转换的图片。这也意味着,最初在视口中渲染但后来被推出视图的元素仍会报告其初始视口内尺寸。
示例
下面列举了一些示例来说明何时会在一些热门网站上发生 Largest Contentful Paint:
在这两个时间轴中,最大的元素(以绿色突出显示)会随着内容加载而变化。在第一个示例中,系统向 DOM 中添加了新内容,并改变了最大的元素。在第二个示例中,布局发生变化,从视口中移除之前的最大内容元素。
虽然延迟加载的内容通常会比网页上已有的内容大,但情况并不一定如此。以下两个示例展示了在网页完全加载之前发生的 LCP。
在第一个示例中,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,您必须添加 iframe。子帧可以使用该 API 将其
largest-contentful-paint
条目报告给父帧以进行聚合。 - 该 API 从导航开始测量 LCP。对于预渲染的网页,请改为从
activationStart
测量 LCP,因为它对应于用户遇到的 LCP 时间。
我们建议开发者使用 web-vitals
JavaScript 库来衡量 LCP,该 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 时间并使用实验室数据进行深入分析和优化的过程。
其他资源
更新日志
有时,bug 会在用于衡量指标的 API 中发现,有时会在指标本身的定义中发现。因此,有时必须进行更改,这些更改可能会在内部报告和信息中心内显示为改进或回归。
为了帮助您管理这一点,变更日志中列出了对这些指标的实现或定义的所有更改。
如果您对这些指标有反馈意见,请在 web-vitals-feedback Google 网上论坛中提供。