Largest Contentful Paint (LCP) 详解
发布日期: 2019年8月8日
最后更新: 2025年3月20日
浏览器支持
- Chrome: 77+
- Firefox: 79+
- Safari: 16.4+
- Edge: 122+
概述
Largest Contentful Paint (LCP) 是 Core Web Vitals 中用于衡量感知加载速度的重要且稳定的指标。它标志着页面加载时间轴中,主要内容可能已经加载完成的时间点。较快的 LCP 能够让用户确信页面内容已准备就绪。
长期以来,测量网页主要内容加载并呈现给用户的时间一直是 web 开发者面临的挑战。传统的指标如 load 和 DOMContentLoaded 由于不一定与用户实际看到的屏幕内容相符,效果并不理想。而 First Contentful Paint (FCP) 等以用户为中心的新型性能指标,仅能捕捉加载过程的极早期阶段。如果页面显示启动画面或加载指示器,这个时间点对用户来说关联性不大。
虽然我们曾推荐过 First Meaningful Paint (FMP) 和 Speed Index (SI) 等性能指标(两者均在 Lighthouse 中提供),它们能够更好地反映首次绘制后的加载体验,但这些指标复杂难懂,且常常存在误差,无法准确识别页面主要内容加载完成的时机。
基于 W3C Web 性能工作组的讨论和 Google 内部的研究,我们得出结论:衡量页面主要内容加载时间的更准确方法是观察最大元素的渲染时间。
什么是 LCP?
LCP 衡量的是视口内最大图片、文本块或视频的渲染时间,计算起点为用户首次导航到页面的时刻。
重要提示: LCP 包含了前页卸载时间、连接建立时间、重定向时间以及其他 TTFB (Time To First Byte) 延迟。在现场测量时,这些延迟可能会更加明显,导致实验室环境和实际用户测量结果之间产生差异。
理想的 LCP 分数
为了提供优秀的用户体验,建议将 Largest Contentful Paint 控制在 2.5 秒以内。为确保大多数用户都能达到这一目标,建议在移动设备和桌面设备上测量页面加载的 75 百分位数。
良好 LCP 值:< 2.5 秒
有关此推荐标准背后的研究和方法论,请参阅 Core Web Vitals 指标阈值定义。
哪些元素会被考虑?
根据 Largest Contentful Paint API 规范,以下元素类型符合 LCP 候选条件:
<img>元素(使用首帧显示时间,适用于 GIF 和动画 PNG 等动画内容)<svg>元素内的<image>元素<video>元素(使用海报图片加载时间或视频首帧显示时间中较早者)- 通过
url()函数加载背景图片的元素(不包括 CSS 渐变) - 包含文本节点或其他行内级文本元素子元素的块级元素
注意: 虽然动画和视频首帧的显示时间尚未在 Web 公开 API 中开放用于 LCP 测量,但在 Chrome 用户体验报告 (CrUX) 数据中可用。
我们将元素限制在此有限集合内是为了降低复杂性。随着研究的深入,未来可能会添加更多元素,包括对 <svg> 的完整支持。
在 LCP 测量中,不仅只有特定元素被考虑,系统还会使用启发式规则排除用户可能认为”非内容”的元素。在基于 Chromium 的浏览器中,包括:
- 透明度为 0 且用户不可见的元素
- 覆盖整个视口的元素,可能被视为背景而非内容
- 低熵的占位图片或其他可能无法反映页面实际内容的图片
浏览器可能会持续改进这些启发式规则,以更好地符合用户对最大内容元素的期望。
这些”内容包含”启发式规则可能与 First Contentful Paint (FCP) 中使用的规则有所不同。FCP 可能会考虑占位图片或全视口图片等元素,而这些元素在 LCP 中可能不符合候选条件。尽管两者名称中都包含”contentful”,但它们的测量目标不同:FCP 测量任意内容在屏幕上的绘制时间,而 LCP 测量主要内容的绘制时间,因此 LCP 更具选择性。
元素尺寸如何确定?
LCP 报告的元素尺寸通常是用户在视口中看到的可见尺寸。如果元素延伸到视口之外,部分被裁剪或存在不可见的溢出,这些部分不计入元素尺寸。
对于从固有尺寸调整大小的图片元素,报告尺寸为显示尺寸和固有尺寸中较小的一个。
对于文本元素,LCP 仅考虑包含所有文本节点的最小矩形。
对于所有元素,LCP 不考虑通过 CSS 应用的外边距、内边距和边框。
注意: 确定哪些文本节点属于哪个元素可能具有挑战性,特别是对于包含行内元素、纯文本节点以及块级子元素的元素。关键在于,所有文本节点都属于其最近的块级祖先元素,且仅属于该元素。规范术语:每个文本节点都属于其包含块元素。
LCP 何时报告?
由于网页是逐步加载的,页面上的最大元素可能会发生变化。
为了处理这种变化,浏览器在绘制第一帧后立即分派一个 largest-contentful-paint 类型的 PerformanceEntry,用于识别最大的内容元素。然而,在渲染后续帧时,每当 Largest Contentful Element 发生变化,就会分派另一个 PerformanceEntry。
例如,对于包含文本和英雄图片的页面,浏览器可能首先仅渲染文本。此时,浏览器会分派一个 largest-contentful-paint 条目,其 element 属性可能引用 <p> 或 <h1>。随后,当头部图片加载完成后,会分派第二个 largest-contentful-paint 条目,其 element 属性引用 <img>。
只有当元素被渲染并呈现给用户时,才会被视为包含内容的最大元素。尚未加载的图片不被视为”已渲染”,使用网页字体且处于字体阻塞期内的文本节点也不计入。在这些情况下,较小的元素可能会被报告为最大内容元素。然而,一旦较大元素完成渲染,就会创建新的 PerformanceEntry。
不仅延迟加载的图片和字体会导致这种情况,当新内容可用时,页面可能会向 DOM 添加新元素。如果这些新元素中的任何一个大于之前的最大内容元素,也会报告新的 PerformanceEntry。
即使当前的最大内容元素被移出视口或从 DOM 中移除,只要没有更大的元素渲染,它仍将保持为最大内容元素。
当用户与页面交互时(如点击、滚动、按键),浏览器会停止报告新条目,因为交互通常会改变用户可见的内容(尤其是滚动时)。
出于分析目的,应仅将最近分派的 PerformanceEntry 报告给分析服务。
注意: 如果用户在后台标签页中打开页面,则可能直到用户聚焦该标签页时才会分派 largest-contentful-paint 条目。在这种情况下,LCP 可能远晚于页面初始加载时间。Google 的 LCP 测量工具不会报告在后台加载的页面,因为这不反映用户感知的加载时间。
加载时间与渲染时间
出于安全原因,最初对于未设置 Timing-Allow-Origin 头的跨域图片,不会公开其渲染时间戳,仅公开加载时间(这已在许多其他 Web API 中公开)。
通常,加载时间稍晚于资源下载完成之后(资源定时的 responseEnd),因为浏览器在下载完成后需要时间来处理资源。然而,当 LCP 资源被预加载或渲染被延迟时,加载时间和渲染时间之间可能存在显著差异。
这可能导致一种看似不可能的情况:通过 Web API 报告的 LCP 时间早于 FCP 时间。实际上并非如此,只是安全限制造成了这种表象。
此问题已在 2024 年下半年得到解决,从 Chrome 133 开始,即使未指定 Timing-Allow-Origin,渲染时间也会被略微延长。
如果可能,建议设置 Timing-Allow-Origin 头,这将提高指标准确性,尤其是在尚未反映最新变更的浏览器中。
元素布局和尺寸变更如何处理?
为了降低计算和分派新性能条目的性能开销,元素尺寸或位置的变更不会生成新的 LCP 候选。仅考虑元素的初始尺寸和其在视口中的位置。
这意味着,最初在屏幕外渲染随后移动到屏幕上的图片可能不会被报告。同样,最初在视口内渲染的元素被推至视口外时,仍会报告其最初的视口内尺寸。
示例
以下是几个常见网站中 Largest Contentful Paint 发生时间的示例:


在这两个时间线中,随着内容加载,最大元素发生了变化。第一个示例中,DOM 中添加了新内容导致最大元素变更;第二个示例中,布局变化导致先前最大的内容被移出视口。
虽然延迟加载的内容通常比页面上已存在的内容更大,但并非总是如此。以下两个示例显示 LCP 在页面完全加载前就已发生:

在此示例中,Instagram 徽标在较早阶段加载完成,并在其他内容逐步显示时保持为最大元素。
注意: Instagram 时间线的第一帧中,相机徽标周围可能没有绿色框。因为它是 <svg> 元素。目前,<svg> 元素本身不被视为 LCP 候选(但 <svg> 内的 <image> 元素和 <video> 元素是候选)。第一个 LCP 候选是第二帧中的文本。

在此 Google 搜索结果页面示例中,在图片或徽标加载完成前显示的文本段落是最大元素。由于所有单个图片都小于此段落,因此它在整个加载过程中保持为最大元素。
如何测量 LCP
LCP 可在实验室或现场环境中测量,以下工具支持此指标:
现场工具
- Chrome 用户体验报告
- PageSpeed Insights
- Search Console (Core Web Vitals 报告)
- web-vitals JavaScript 库
实验室工具
- Chrome DevTools
- Lighthouse
- PageSpeed Insights
- WebPageTest
使用 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 条目记录到控制台,实际使用 JavaScript 测量 LCP 更为复杂。有关详细信息,请参阅指标与 API 的差异。
在上面的示例中,每个记录的 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 内的元素,但指标应考虑,因为它们是页面用户体验的一部分。对于 LCP 位于 iframe 内的页面(如嵌入式视频的海报图片),这将表现为 CrUX 与 RUM 之间的差异。要正确测量 LCP,必须考虑这些因素。子框架可以使用 API 将
largest-contentful-paint条目报告给父框架进行聚合。
与其记住所有这些细微差别,不如使用 web-vitals JavaScript 库来测量 LCP,它会自动处理这些差异(如果可能。iframe 相关问题除外)。
import {onLCP} from 'web-vitals';
// 一旦 LCP 可用,立即测量并记录
onLCP(console.log);
有关使用 JavaScript 测量 LCP 的完整示例,请参阅 onLCP() 源代码。
注意: 在某些情况下,可能无法使用 JavaScript 测量 LCP,例如跨域 iframe。有关详细信息,请参阅 web-vitals 库的限制部分。
如果最大元素不是最重要的怎么办?
页面上最重要的元素(一个或多个)可能与最大元素不一致。开发者可能对其他元素的渲染时间感兴趣,这可以使用 Element Timing API 来实现,如自定义指标文章中所述。
如何改进 LCP
完整的 LCP 优化指南 介绍了如何通过现场数据识别 LCP 问题,并利用实验室数据进行深入分析和优化。
参考资料
- 从 Chrome 性能监控中学到的经验教训(Annie Sullivan, performance.now(), 2019)
变更日志
在用于测量指标的 API 或指标定义本身中,有时会发现错误,因此需要进行更改。这些变更可能反映在内部报告和仪表板中,表现为改进或下降。
所有关于这些指标实现或定义的变更都将记录在此变更日志中。
如果您对这些指标有反馈,请在 web-vitals-feedback Google 群组中提交。
正在加载评论...