什么是最大内容绘制(LCP)?以及如何改进它
用户对网站的第一印象,取决于它看起来加载得有多快。最大的元素通常是特色图片,也可能是 <h1> 标签,但也可能是以下任意一种:<img> 元素、<svg> 元素中的 <image>、<video> 元素中的图像,或通过 url() 函数加载的背景图。
最大内容绘制(LCP,Largest Contentful Paint)指视口内单个最大可见元素完成加载所需的时间。它代表网站在视觉上已完成加载,是 Google 用于衡量页面体验的三项核心网页指标(CWV)之一。
用户对网站的第一印象,取决于它看起来加载得有多快。
最大的元素通常是特色图片,也可能是 <h1> 标签,但它也可能是以下任意一种:
- <img> 元素
- <svg> 元素中的 <image> 元素
- <video> 元素中的图像
- 通过 url() 函数加载的背景图
确定元素大小时,视口之外或溢出的部分不会被考虑在内。如果一张图片占满了整个视口,它不会被纳入 LCP 计算。
下面看看 LCP 应该有多快,以及如何改进它。
理想的 LCP 值是多少?
理想的 LCP 值小于 2.5 秒,且应基于 Chrome 用户体验报告(CrUX)数据,即来自访问你网站、并选择分享该信息的真实 Chrome 用户的数据。需要 75% 的页面访问在 2.5 秒或更短时间内完成加载。
页面可能被归入以下几档之一:
- 良好:<=2.5 秒
- 有待改进:>2.5 秒且 <=4 秒
- 较差:>4 秒

LCP 数据
截至 2023 年 4 月,57.1% 的网站处于良好的 LCP 档位,这是整个站点的平均值。如前所述,需要 75% 的页面访问在 2.5 秒或更短时间内加载,才会在这里显示为“良好”。

LCP 是人们最难改进的一项核心网页指标。

我们开展过一项关于核心网页指标的研究,结果发现,与桌面端相比,页面在移动设备上更不容易获得良好的 LCP 值。

在较慢的网络连接下,LCP 阈值似乎几乎不可能达标。

如何衡量 LCP
衡量 LCP 有几种不同方式,需要关注两类数据:字段数据(field data)和实验室数据(lab data)。
字段数据来自 Chrome 用户体验报告(CrUX),即选择分享数据的真实 Chrome 用户所产生数据。它最能反映真实世界中不同网络条件、设备、缓存等环境下的 LCP 表现,Google 实际用于评估核心网页指标的也是它。
实验室数据基于在相同条件下运行的测试,以便测试可重复。Google 并不用它评估核心网页指标,但它对测试很有用,因为 CrUX/字段数据是 28 天的滚动平均值,要看到改动的影响需要等待一段时间。
衡量 LCP 的最佳工具取决于所需的数据类型(实验室/字段),以及需要的是单个 URL 还是多个 URL。
衡量单个 URL 的 LCP
Pagespeed Insights 能拉取页面级的字段数据,而这类数据在 CrUX 数据集中无法直接查询。它还会基于 Google Lighthouse 运行实验室测试,并提供源(origin)数据,让单个页面的性能可以与整个网站比较。
衡量多个 URL 或整个网站的 LCP
可以在 Google Search Console 中获取 CrUX 数据,它分为良好、有待改进和较差三个类别。

点击其中任何一个问题,就能看到受影响页面分组的明细。分组指数值相近、很可能使用同一模板的页面,只需在模板中改一次,该分组内所有页面就会一并修复。

如果需要大规模的实验室数据和字段数据,唯一的途径是通过 PageSpeed Insights API。可以用 Ahrefs 的 Site Audit 轻松接入,并获得详尽的性能报告。对已通过验证的网站,只要有 Ahrefs Webmaster Tools(AWT)账号,这项功能就是免费的。

用 Site Audit 免费检查包括 LCP 在内的核心网页指标
请注意,显示的核心网页指标数据取决于你在抓取设置中选用的 user-agent。从移动端抓取,就会从 API 获得移动端的 CWV 值。
免费工具:一次检查最多 10 个页面或网站的桌面与移动端 CWV 及 Lighthouse 指标
这是另一个免费工具,可用它一次检查最多 10 个页面或网站,看看自己与竞争对手相比如何。
设置:
- 在指定输入框中填入 Google PageSpeed Insights API 密钥。(了解如何生成 API 密钥,见此处。)
- 添加想分析的 URL(每行一个)。
运行分析:
- 点击 "Check CWV" 按钮开始获取指标。进度指示器会显示请求的状态。
查看结果:
- 结果会以分类清晰的评分卡形式展示:
- 每项指标都用颜色标注以体现性能:
核心网页指标批量检查器
这是一个示例输出,展示速度评分卡的样子,可以把它当作独立工具来用:网站速度测试。
如何改进 LCP
在 PageSpeed Insights 中,LCP 元素会在“Diagnostics(诊断)”部分标明。那里还有一个可选择 LCP 的标签页,只显示与 LCP 相关的问题。这些就是实验室测试中发现、需要解决的问题。

与 LCP 相关的问题很多,这使它成为最难改进的指标。
理论听起来很简单:把最大的元素更快地呈现出来。但在实践中会变得相当复杂:有些文件可能需要先加载其他文件,浏览器中也可能存在相互冲突的优先级。你可能修复了一大堆问题,却没看到实际改善,这很令人沮丧。
如果不太懂技术,又不想请人,就为所用系统找找性能或页面速度优化插件、模块或软件包。可以把下面的信息当作一份指南,判断自己可能需要哪些功能。
以下是几种改进 LCP 的方法:
1. 找到你的 LCP 元素
在 PageSpeed Insights 中点击“Diagnostics(诊断)”部分的“Largest Contentful Paint element(最大内容绘制元素)”,它会识别出 LCP 元素。

2. 为资源加载排定优先级
要通过 LCP 检查,应当对资源在关键渲染路径中的加载方式排定优先级,也就是重新安排资源被下载和处理的顺序。
应先加载 LCP 元素所需的资源,以及首屏内容所需的其他资源。等用户最初可见的元素加载完成,再加载其余部分。
许多网站只要为主图以及必要的样式表和字体添加一些早期提示(early hints)或 preload 声明,就能让 LCP 达到合格时间。下面看如何优化各类资源。
图片尽早加载
如果不需要这张图片,最有效的做法就是直接去掉。如果必须保留,建议优化尺寸和质量,让它尽可能小。
还可以使用 Early Hints。fetchpriority=”high” 可以用在 <img> 或 <link> 标签上,告诉浏览器尽早获取图片,这意味着它会稍早一点显示出来。
Early Hints 并非在所有浏览器上都有效,因此还可以预加载图片。这会稍早一点开始下载图片,但不如 fetchpriority=”high” 那么早。
一张响应式图片的 preload 声明长这样:
[['Text', '<link rel="preload" as="image" href=“cat.jpg"']]
[['Text', 'imagesrcset=“cat_400px.jpg 400w,']]
[['Text', 'cat_800px.jpg 800w, cat_1600px.jpg 1600w"']]
[['Text', 'imagesizes="50vw">']]
你甚至可以把 fetchpriority=”high” 和 preload 一起使用!
图片延后加载
对不立即需要的图片,都应做懒加载。这会在流程较后阶段、或用户即将看到它们时才加载图片。可以像这样使用 loading=“lazy”:
[['Text', '<img src=“cat.jpg" alt=“cat" loading="lazy">']]
不要对首屏以上的图片做懒加载!
CSS 尽早加载
应当压缩(minify)所有 CSS,如有可能还要删除未使用的 CSS。
另一件重要的事是内联关键 CSS:把加载用户立即看到的内容所需的 CSS 提取出来,直接嵌入 HTML。当 HTML 下载完成时,加载用户所见内容所需的全部 CSS 就已可用。

CSS 延后加载
对所有非关键的额外 CSS,应让它在流程较后阶段才生效。可以先用 preload 声明开始下载 CSS,但直到稍后通过 onload 事件才应用它。如下所示:
[['Text', '<link rel="preload" href="stylesheet.css" as="style" onload="this.rel=\'stylesheet\'">']]
字体
这里给出几个选项:
良好:预加载字体。如果能用同一台服务器来消除连接,则更好。
更好:Font-display: optional。它可以与 preload 声明搭配使用,给字体一小段加载时间窗口。如果字体没能及时加载,初次页面加载会显示默认字体,之后自定义字体会被缓存,并在后续页面加载时显示。
最佳:直接用系统字体。没有任何需要加载的东西,也就没有延迟。
JavaScript 尽早加载
前面已谈到删除未使用的 JavaScript 并压缩现有代码。如果使用 JavaScript 框架,可能想对页面做预渲染(prerender)或服务端渲染(SSR)。
也可以把早期需要的 JavaScript 内联,原理与 CSS 部分相同:把 JavaScript 文件中的部分内容移到 HTML 中一并加载。
另一种选择是预加载 JavaScript 文件,以便更早获取。这应当只针对加载首屏内容所需的资源,或某些功能所依赖的 JavaScript。
JavaScript 延后加载
对任何不立即需要的 JavaScript,都应稍后加载。主要有两种方式——defer 和 async 属性,可以加到 script 标签上。
通常情况下,脚本在下载和执行时会阻塞解析器。Async 会让解析和下载同时进行,但在脚本执行期间仍会阻塞解析。Defer 在下载期间不会阻塞解析,且只会在 HTML 解析完成后才执行。

该用哪个?对任何希望尽早执行、或有依赖关系的内容,我会倾向于 async。
比如,我倾向于对分析(analytics)标签使用 async,以便记录到更多用户。对直到稍后才需要、或没有依赖关系的内容,则适合用 defer。这些属性添加起来相当容易。
看看这些示例:
普通:
[['Text', '<script src="https://www.domain.com/file.js"></script>']]
Async:
[['Text', '<script src="https://www.domain.com/file.js" async></script>']]
Defer:
[['Text', '<script src="https://www.domain.com/file.js" defer></script>']]
3. 让文件更小
如果能去掉一些文件或缩小它们的体积,页面就会加载得更快。这意味着可能想删除不再使用的文件或不使用的部分代码。
具体做法很大程度取决于环境配置,但移除文件中不需要的部分这一过程通常被称为 tree shaking。
使用 JavaScript 框架时,这通常通过 Webpack 或 Grunt 的自动化流程完成,有时像 WordPress 这样的系统也能做到,但多数常见 CMS 系统可能不支持。
可以跳过这一步,或者看看所用系统有没有带此选项的插件。
要让文件更小,通常需要压缩它们。
几乎用于构建网站的所有文件类型都能被压缩,包括 CSS、JavaScript、图片和 HTML。此外,几乎每个系统和服务器都支持压缩。
这通常在服务器或 CDN 层面完成,但有些插件也支持,比如用于 WordPress 的 WP Rocket。
4. 让文件更靠近用户
信息的传输需要时间,离服务器越远,数据传输所需的时间越长。除非只服务一小片地理区域,否则使用内容分发网络(CDN)是个好主意。
CDN 能以更靠近用户的方式连接并提供网站,就像在世界各地拥有服务器的副本。
5. 将资源托管在同一台服务器上
首次连接到一台服务器时,有一个过程会遍历网络,在你和服务器之间建立安全连接。
这需要一些时间,而每个需要新建的连接在走完同样流程时都会带来额外延迟。把资源托管在同一台服务器上,就能消除这些额外延迟。
如果无法使用同一台服务器,可以用 preconnect 或 DNS-prefetch 更早地建立连接。浏览器通常会在开始连接前等待 HTML 下载完成,但有了 preconnect 或 DNS-prefetch,它会比平时更早开始。请注意,DNS-prefetch 的浏览器支持比 preconnect 更好。
对每个想尽早获取的资源,都要加一条像这样的新声明:
[['Text', '<link rel="preconnect" href="https://fonts.googleapis.com/">']]
[['Text', '<link rel="dns-prefetch" href="https://fonts.googleapis.com/" />']]
6. 使用缓存
缓存资源后,它们在首次页面访问时会被下载,但后续页面访问中无需再次下载。资源已经就绪,额外的页面加载会快得多。
看看下面瀑布图中,第二次页面加载时下载的文件有多么少。
页面首次加载:

页面第二次加载:

如有可能,也在 CDN 上缓存,缓存时长以自己感到舒适的时长为准。
理想的配置是缓存非常长的时间,但在页面发生改动时清除缓存。
7. 其他
还有一些其他技术可能有助于性能,也值得关注,包括 Speculative Prerendering、Signed Exchanges 和 HTTP/3。
最后总结
有没有更好的指标来衡量可见加载?目前看不到有什么新东西即将出现。为衡量加载,我们已经历过好几次演变。
Load 和 DOMContentLoaded 并不能真正说明用户看到了什么。First Contentful Paint(FCP,首次内容绘制)是加载体验的起点。First Meaning Paint(FMP,首次有意义绘制)和 Speed Index(SI,速度指数)都很复杂,且并不能真正识别主要内容何时完成加载。
如有任何疑问,可以在 Twitter 上给我发消息。