Largest Contentful Paint (LCP)

浏览器支持

  • 77
  • 79
  • 122
  • x

来源

过去,衡量网页主要内容加载和对用户可见的速度一直是 Web 开发者面临的一项挑战。loadDOMContentLoaded 等较旧的指标效果不佳,因为它们与用户在屏幕上看到的内容不一定对应。以用户为中心的较新性能指标(如 First Contentful Paint (FCP))只能捕获加载体验的初始阶段。如果网页显示启动画面或加载指示器,这一时刻与用户不太相关。

过去,我们推荐过首次有效绘制 (FMP)速度指数 (SI)(均在 Lighthouse 中提供)等性能指标,以帮助捕获初始绘制后的更多加载体验,但这些指标复杂、难以解释且经常出错 - 这意味着它们仍然无法确定网页的主要内容何时加载完毕。

根据 W3C 网络性能工作组中的讨论和 Google 所做的研究,我们发现,如果要更准确地衡量网页主要内容的加载时间,请查看最大元素的呈现时间。

什么是 LCP?

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

LCP 得分是多少?

为了提供良好的用户体验,网站应尽力将 Largest Contentful Paint 的时长控制在 2.5 秒或更短。为确保大多数用户都能达到此目标,建议将网页加载的第 75 个百分位作为阈值衡量,并按移动设备和桌面设备细分。

<ph type="x-smartling-placeholder"></ph> 良好的 LCP 值为 2.5 秒或更短,不良值超过 4.0 秒,介于 2.5 秒之间的所有值都需要改进
理想的 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) 使用的算法不同,FCP 可能会考虑其中一些元素,例如占位图片或完整视口图片,即使它们不符合 LCP 候选条件。尽管两者都使用“contentful”但这些指标的目的有所不同。FCP 会衡量何时将任何内容绘制到屏幕上,以及 LCP 何时绘制到主内容,以便提高 LCP 的选择性。

元素大小是如何确定的?

针对 LCP 报告的元素的尺寸通常是用户在视口内可见的尺寸。如果元素延伸到视口之外,或者任何元素被截断或具有不可见的“溢出”,则这些部分不会计入元素的尺寸。

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

对于文本元素,LCP 仅考虑可包含所有文本节点的最小矩形。

对于所有元素,LCP 不会考虑使用 CSS 应用的外边距、内边距或边框。

何时报告 LCP?

网页通常会分阶段加载,因此,网页上最大的元素可能会发生变化。

为了应对这种可能的变更,浏览器会在绘制完第一帧后,立即分派类型为 largest-contentful-paintPerformanceEntry,用于识别最大的内容元素。但是,在渲染后续帧后,只要最大的内容元素发生变化,它就会分派另一个 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 何时会在一些热门网站上出现:

来自 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。以下示例展示了如何创建 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 时间并使用实验室数据进行深入分析和优化的流程。

其他资源

更新日志

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

为帮助您应对此问题,对这些指标的实现或定义所做的所有更改都会显示在此更新日志中。

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