过去,衡量网页主要内容加载和对用户可见的速度一直是网络开发者面临的一项挑战。load 或 DOMContentLoaded 等较旧的指标效果不佳,因为它们与用户在屏幕上看到的内容不一定对应。而首次内容渲染 (FCP) 等以用户为中心的新型性能指标仅捕获加载体验的开头部分。如果网页显示启动画面或显示加载指示器,此时刻与用户的相关性不高。
过去,我们曾建议使用 First Meaningful Paint (FMP) 和 Speed Index (SI)(这两个指标均可在 Lighthouse 中找到)等性能指标,以帮助捕获初始绘制之后的更多加载体验,但这些指标很复杂、难以解释,并且经常出错,也就是说,它们仍然无法确定网页的主要内容何时加载完毕。
根据 W3C 网络性能工作组中的讨论和 Google 所做的研究,我们发现,如果要更准确地衡量网页主要内容的加载时间,请查看最大元素的呈现时间。
什么是 LCP?
LCP 会报告视口中可见的最大图片、文本块或视频的呈现时间(相对于用户首次导航到相应网页的时间)。
LCP 得分多少算好?
为了提供良好的用户体验,网站应尽力将 Largest Contentful Paint 控制在 2.5 秒或更短内。为确保大多数用户都能达到此目标值,一个合适的衡量阈值是网页加载时间的第 75 个百分位数,并按移动设备和桌面设备进行细分。
系统会考虑哪些元素?
如 Largest Contentful Paint API 中当前所指定,考虑最大内容渲染时间的元素类型包括:
<img>
元素(第一帧呈现时间适用于 GIF 或动画 PNG 等动画内容)<svg>
元素内的<image>
元素<video>
元素(使用海报图片加载时间或视频的第一帧呈现时间,以两者中较早达到者为准)- 使用
url()
函数加载背景图片的元素(而不是 CSS 渐变) - 包含文本节点或其他内嵌级文本元素子级的块级元素。
请注意,我们有意将元素限制为这一有限集合,以便在开始时保持简单。随着研究的深入,未来可能会添加其他元素(例如完全支持 <svg>
)。
除了仅考虑某些元素之外,LCP 衡量结果还会使用启发词语来排除用户可能会视为“无内容”的某些元素。对于基于 Chromium 的浏览器,包括:
- 不透明度为 0 且对用户不可见的元素
- 覆盖整个视口的元素,此类元素可能会被视为背景(而非内容)
- 占位符图片或其他具有低熵的图片,可能无法反映网页的实际内容
浏览器可能会继续改进这些启发法,确保我们能满足用户对最大的内容元素的预期。
这些“内容”启发词语可能与 First Contentful Paint (FCP) 使用的启发词语不同,后者可能会考虑其中一些元素(例如占位符图片或整个视口图片),即使它们不符合 LCP 候选条件也是如此。虽然这两个指标的名称中都使用了“内容丰富”一词,但它们的目标不同。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});
在上面的示例中,每个记录的 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 在 performance.now() 大会 (2019) 上发表的演讲“从 Chrome 性能监控中总结出的经验”
更新日志
有时,错误是在用于衡量指标的 API 中发现的,有时是在指标本身的定义中发现的。因此,有时必须进行更改,这些更改可能会在内部报告和信息中心中显示为改进或回归。
为帮助您应对此问题,对这些指标的实现或定义所做的所有更改都会显示在此更新日志中。
如果您对这些指标有任何反馈,可以通过 web-vitals-feedback Google 群组提供反馈。