Largest Contentful Paint (LCP)

浏览器支持

  • 77
  • 79
  • 122
  • x

来源

长期以来,衡量网页主要内容的加载速度以及对用户可见是一个一直以来的挑战。loadDOMContentLoaded 等旧指标效果不佳,因为它们不一定与用户在屏幕上看到的内容相对应。而较新的以用户为中心的性能指标(例如 First Contentful Paint (FCP))仅捕获加载体验的开始阶段。如果网页显示启动画面或显示加载指示器,则这一时刻与用户没有太大关系。

过去,我们会推荐首次有效渲染时间 (FMP)速度指数 (SI)(两者均在 Lighthouse 中提供)等性能指标,以帮助捕捉更多初始绘制后的加载体验,但这些指标比较复杂,难以解释,而且往往是错误的,也就是说,它们仍然无法确定网页主要内容的加载时间。

根据 W3C Web 性能工作组中的讨论和 Google 的研究,我们发现,衡量页面主要内容的加载时间的更准确方法是查看最大的元素的呈现时间。

什么是 LCP?

LCP 报告的是视口中可见最大图片或文本块相对于用户首次导航到网页的呈现时间。

良好的 LCP 得分是多少?

为了提供良好的用户体验,网站应努力将 Largest Contentful Paint 控制在 2.5 秒以内。为确保您的大多数用户都达到此目标,最好衡量一下网页加载的第 75 个百分位(按移动设备和桌面设备细分)。

良好 LCP 值为 2.5 秒或更短,不良值大于 4.0 秒,两者之间的任何值都需要改进
良好的 LCP 值为 2.5 秒或更短。

需要考虑哪些元素?

根据 Largest Contentful Paint API 中当前的规定,Largest Contentful Paint 考虑的元素类型包括:

  • <img> 元素(第一帧呈现时间用于 GIF 或动画 PNG 等动画内容)
  • <svg> 元素内的 <image> 元素
  • <video> 元素(系统会使用视频的海报图片加载时间或第一帧显示时间,以较早者为准)
  • 一个元素,带有使用 url() 函数(而不是 CSS 渐变)加载的背景图片
  • 包含文本节点或其他内嵌级文本元素子元素的块级元素。

请注意,将元素限制在这一有限集合内是我们有意为之,目的是在开始时尽量简单。随着开展更多研究,未来可能会添加其他元素(例如完全的 <svg> 支持)。

除了仅考虑部分元素之外,LCP 衡量功能还会使用启发法来排除用户可能会认为“无内容”的特定元素。对于基于 Chromium 的浏览器,其中包括:

  • 不透明度为 0 的元素,用户看不到这些元素
  • 覆盖整个视口的元素可能被视为背景而非内容
  • 占位符图片或其他低熵图片,可能无法反映网页的实际内容

浏览器可能会继续改进这些启发词语,以确保达到用户对最大的内容元素是什么的预期。

这些“内容性”启发式算法可能与 First Contentful Paint (FCP) 使用的启发法不同,后者可能会考虑其中部分元素(例如占位符图片或完整视口图片),即使它们不符合 LCP 候选条件也是如此。尽管两者的名称中都使用了“contentful”,但这两个指标的目的却不同。FCP 衡量的是任何内容绘制到屏幕上的时间,LCP 用于绘制主要内容,以便 LCP 更有选择性。

如何确定元素的大小?

针对 LCP 报告的元素尺寸通常是用户在视口内可见的尺寸。如果该元素延伸至视口之外,或者有任何元素被剪裁或存在不可见“溢出”,这些部分就不会计入元素的尺寸。overflow

对于根据固有尺寸调整过大小的图片元素,报告的尺寸为可见尺寸或固有尺寸(以较小者为准)。

对于文本元素,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 公开)。

这可能会导致一种看似不可能的情况,即 Web API 报告的 LCP 早于 FCP。事实并非如此,而是由于此安全限制而出现。

如果可能,我们始终建议您设置 Timing-Allow-Origin 标头,以便指标更加准确。

如何处理元素布局和尺寸更改?

为了降低计算和调度新的性能条目的性能开销,对元素的大小或位置所做的更改不会生成新的 LCP 候选版本。系统只会考虑元素的初始尺寸和在视口中的位置。

也就是说,系统可能不会报告最初在屏幕外呈现后又在屏幕上过渡的图片。这也意味着,最初在视口中渲染但后来被下推,而不会显示在视图之外的元素仍会报告其初始视口内尺寸。

示例

下面列举了一些示例来说明何时会在一些热门网站上发生 Largest Contentful Paint:

来自 cnn.com 的 Largest Contentful Paint 时间轴
来自 cnn.com 的 LCP 时间轴。
来自 techcrunch.com 的 Largest Contentful Paint 时间轴
来自 techcrunch.com 的 LCP 时间轴。

在上面的两个时间轴中,最大的元素会随着内容加载而变化。在第一个示例中,我们向 DOM 添加了新内容,并改变了最大的元素。在第二个示例中,布局会发生变化,之前最大的内容已从视口中移除。

虽然延迟加载的内容通常会大于网页上已有的内容,但其实并非如此。以下两个示例显示的是在网页完全加载之前发生的 LCP。

来自 instagram.com 的 Largest Contentful Paint 时间轴
来自 instagram.com 的 LCP 时间轴。
来自 google.com 的 Largest Contentful Paint 时间轴
来自 google.com 的 LCP 时间轴。

在第一个示例中,Instagram 徽标的加载时间相对较早,即使其他内容逐渐显示,该徽标也仍然是最大的元素。在 Google 搜索结果页示例中,最大的元素是在任何图片或徽标加载完毕之前显示的一段文本。由于所有单独的图片都小于此段落,因此在整个加载过程中,该图片仍然是最大的元素。

如何衡量 LCP

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,您应考虑 LCP。子框架可以使用该 API 将其 largest-contentful-paint 条目报告给父框架以进行汇总。
  • API 从导航开始就测量 LCP,但对于预渲染的网页,LCP 应从 activationStart 开始测量,因为 LCP 对应于用户实际体验到的 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 计时的过程,并使用实验室数据进行深入分析和优化。

其他资源

更新日志

有时,bug 会在用于衡量指标的 API 中发现,有时会在指标本身的定义中发现。因此,有时必须进行更改,这些更改可能会以改进或回归的形式显示在内部报告和信息中心内。

为了帮助您管理这些变更,这些指标的实现或定义方面的所有更改都会显示在此更新日志中。

如果您对这些指标有反馈意见,可以在 web-vitals-feedback Google 网上论坛中提供。