优化 Largest Contentful Paint

关于如何分解 LCP 并确定需要改进的关键部分的分步指南。

Largest Contentful Paint (LCP)Core Web Vitals 的三个指标之一,代表网页主要内容的加载速度。具体来说,LCP 用于测量从用户开始加载网页到在视口内呈现最大的图片或文本块之间的时间。

为了提供良好的用户体验,网站应力求至少有 75% 的网页访问的 LCP 不超过 2.5 秒

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder"></ph> 良好的 LCP 值为 2.5 秒或更短,不良值超过 4.0 秒,介于 2.5 秒之间的所有值都需要改进
理想的 LCP 值为 2.5 秒或更短。

很多因素都会影响浏览器加载和渲染网页的速度,而其中任何环节出现的延迟都会对 LCP 产生重大影响。

快速修复网页的单个部分无法显著改善 LCP 的情况很少见。要改进 LCP,您必须关注整个加载过程,确保其中的所有步骤都得到优化。

了解 LCP 指标

在优化 LCP 之前,开发者应设法了解自己是否遇到了 LCP 问题,以及此类问题的影响程度。

LCP 可以通过多种工具进行衡量,但并非所有工具都会以相同的方式衡量 LCP。要了解真实用户的 LCP,我们应该关注真实用户的体验,而不是 Lighthouse 或本地测试等基于实验室的工具显示的内容。这些基于实验室的工具可以提供大量信息来解释和帮助您改进 LCP,但请注意,仅凭实验室测试可能无法完全代表实际用户的体验。

基于真实用户的 LCP 数据可通过以下两种方式显示:在网站上安装的真实用户监控 (RUM) 工具,或者通过 Chrome 用户体验报告 (CrUX)(针对数百万个网站收集真实 Chrome 用户的匿名数据)。

使用 PageSpeed Insights CrUX LCP 数据

借助 PageSpeed Insights,您可以访问顶部标为探索真实用户所体验的 CrUX 数据。您可以在底部标有诊断性能问题的部分找到更详细的实验室数据。如果您的网站有 CrUX 数据,应始终先关注真实用户数据。

<ph type="x-smartling-placeholder">
</ph> PageSpeed Insights 中显示的 CrUX 数据 <ph type="x-smartling-placeholder">
</ph> PageSpeed Insights 中显示的 CrUX 数据。
<ph type="x-smartling-placeholder">

PageSpeed Insights 最多可显示四种不同的 CrUX 数据:

  • 此网址移动数据
  • 此网址桌面设备数据
  • 整个移动数据
  • 整个 Origin桌面设备数据

您可以在此部分右上角和右上角的控件中切换这些控件。如果某个网址没有足够的数据,无法在网址一级显示,但有来源的数据,那么 PageSpeed Insights 会始终显示来源数据。

<ph type="x-smartling-placeholder">
</ph> 在无法获得网址级数据的情况下,PageSpeed Insights 会回退到源级数据 <ph type="x-smartling-placeholder">
</ph> 如果 PageSpeed Insights 没有网址级数据,它会显示 源级数据

整个来源的 LCP 可能与具体网页的 LCP 有很大不同,具体取决于相应网页上的 LCP 加载方式(与该来源中的其他网页相比)。访问者浏览这些网页的方式也会影响到网页。首页往往由新用户访问,因此往往是“冷”加载的,没有任何缓存内容,因此网站上速度最慢的网页往往也是如此。

查看四种不同类别的 CrUX 数据有助于您了解 LCP 问题是特定于此网页,还是更常见的网站级问题。同样,它也可以显示哪些设备类型存在 LCP 问题。

使用 PageSpeed Insights CrUX 补充指标

想要优化 LCP 的广告客户还应使用 First Contentful Paint (FCP)Time to First Byte (TTFB) 计时,它们都是很好的诊断指标,可提供有关 LCP 的宝贵数据洞见。

TTFB 是访问者开始导航到网页(例如,点击链接)的时间,直到接收到 HTML 文档的前几字节。较高的 TTFB 可能会使实现 2.5 秒的 LCP 具有挑战性,甚至是无法实现。

TTFB 偏高的原因包括:多个服务器重定向、访问者距离最近的网站服务器较远、访问者网络状况不佳,或因查询参数而导致无法使用缓存内容。

网页开始呈现后,可能会先进行初始绘制(如背景颜色),然后显示某些内容(如网站标题)。初始内容的外观由 FCP 进行衡量。FCP 与其他指标之间的差值非常有价值。

如果 TTFB 和 FCP 之间存在较大差异,则可能表示浏览器需要下载大量会阻塞渲染的素材资源。这也表明网站必须完成大量工作才能呈现任何有意义的内容 - 这是一个非常依赖客户端呈现的网站的典型标志。

如果 FCP 和 LCP 之间存在较大差异,则表示 LCP 资源无法立即供浏览器优先使用(例如,由 JavaScript 管理的文字或图片,而不在初始 HTML 中提供),或者浏览器正在完成其他工作,然后才能显示 LCP 内容。

使用 PageSpeed Insights Lighthouse 数据

PageSpeed Insights 的“Lighthouse”部分提供了一些有关如何改进 LCP 的指南,但首先您应检查提供的 LCP 是否与 CrUX 提供的真实用户数据基本一致。如果 Lighthouse 和 CrUX 不一致,CrUX 可能会提供更准确的用户体验。在对网页执行操作之前,请确保您的 CrUX 数据是针对网页的,而不是完整来源。

如果 Lighthouse 和 CrUX 均显示需要改进的 LCP 值,则“Lighthouse”部分可以就如何改进 LCP 提供有价值的指导。您可以使用 LCP 过滤条件以仅显示与 LCP 相关的审核,如下所示:

<ph type="x-smartling-placeholder">
</ph> Lighthouse LCP 机会和诊断 <ph type="x-smartling-placeholder">
</ph> Lighthouse 用于改进 LCP 的诊断信息和建议。

除了优化建议,还有一些诊断信息或许能提供更多信息来帮您诊断问题。Largest Contentful Paint 元素诊断会显示构成 LCP 的各种时间的实用细分:

<ph type="x-smartling-placeholder">
</ph> Lighthouse 中的 LCP 阶段 <ph type="x-smartling-placeholder">
</ph> Lighthouse 的 LCP 元素细分数据。

接下来,我们将深入介绍这些子部分。

LCP 细分维度

如果 PageSpeed Insights 无法提供如何提高此指标的答案,那么针对 LCP 进行优化可能会是一项较为复杂的任务。对于复杂的任务,通常最好将其分解为更易于管理的小任务,并分别处理每个任务。

本部分将介绍如何将 LCP 分解为最关键的子部分的方法,然后提供具体建议和最佳实践,说明如何优化每个部分。

大多数网页加载通常包含许多网络请求,但为了发现改善 LCP 的机会,您应先从以下两个方面入手:

  1. 初始 HTML 文档
  2. LCP 资源(如果适用)

虽然网页上的其他请求可能会影响 LCP,但这两个请求(具体而言是 LCP 资源的开始和结束时间)可以揭示您的网页是否针对 LCP 进行了优化。

要识别 LCP 资源,您可以使用开发者工具(例如前面介绍的 PageSpeed Insights、Chrome 开发者工具WebPageTest)来确定 LCP 元素。然后,您可以匹配由网页加载的所有资源的广告联盟瀑布流上由相应元素加载的网址(同样,如果适用)。

例如,以下可视化图表会在典型网页加载的网络瀑布图上突出显示这些资源,在该图表中,LCP 元素需要图片请求才能呈现。

<ph type="x-smartling-placeholder">
</ph> 网络广告瀑布流,其中突出显示了 HTML 和 LCP 资源 <ph type="x-smartling-placeholder">
</ph> 一个广告瀑布流图表,其中显示了 网页的 HTML 和 LCP 所需的资源

为了让网页得到充分优化,您应该让 LCP 资源请求尽早开始加载,并希望 LCP 元素在 LCP 资源完成加载后尽快呈现。为了直观了解特定网页是否遵循了此原则,您可以将总 LCP 时间细分为以下子部分:

首字节时间 (TTFB)
从用户开始加载网页到浏览器加载网页之间的时间 接收 HTML 文档响应的第一个字节。
资源加载延迟
从 TTFB 到浏览器开始加载 LCP 资源所用的时间。如果 LCP 元素不需要加载资源即可渲染(例如,如果 元素是以系统字体渲染的文本节点),此时为 0。
资源加载时长
加载 LCP 资源本身所用的时长。如果 LCP 元素不需要加载资源即可渲染,此时为 0。
元素渲染延迟
从 LCP 资源完成加载到 LCP 元素完成加载之间的时间 才能完全呈现

每个网页的 LCP 都由以下四个子类别组成。信息之间不存在空隙或重叠 且两者相加等于完整的 LCP 时间。

<ph type="x-smartling-placeholder">
</ph> LCP 明细,其中显示了四个子类别 <ph type="x-smartling-placeholder">
</ph> 同一瀑布图,叠加了四个 LCP 子类别 。

每个网页的 LCP 值都可以细分为这四个子部分。这两者之间不存在重叠或间断。这些时间加起来等于完整的 LCP 时间。

优化 LCP 时,尝试单独优化这些子部分会很有帮助。但同样重要的是,您需要对所有这些元素进行优化。在某些情况下,对一个部分应用的优化并不会改善 LCP,只会将节省的时间转移到另一个部分。

例如,在早期的网络广告瀑布流中,如果您通过进一步压缩图片或改用更优化的格式(例如 AVIF 或 WebP)来减小图片文件大小,虽然可以缩短资源加载时长,但实际上并不能改善 LCP,因为时间会直接转移到元素渲染延迟子部分:

<ph type="x-smartling-placeholder">
</ph> 与上文所示的 LCP 明细相同,其中资源加载时长子类别缩短了,但总体 LCP 时间保持不变。 <ph type="x-smartling-placeholder">
</ph> 缩短资源加载时长会增加元素渲染延迟时间,而不会降低 LCP。

出现这种情况的原因是,在该页面上,LCP 元素会一直处于隐藏状态,直到 JavaScript 代码加载完毕,而随后又立即显示所有内容。

这个示例有助于说明,您需要优化所有这些子部分,才能实现最佳 LCP 结果。

最佳分段时间

为了优化 LCP 的每个子部分,您必须了解在经过充分优化的网页上,这些子部分的理想细分是什么。

在四个子部分中,有两个子部分包含“延迟”一词。根据此线索,您希望这些时间尽可能接近于零。其他两个部分涉及网络请求,就其性质而言,这需要一定的时间。

LCP 子部分 LCP 占比 (%)
加载第一个字节所需时间 ~40%
资源加载延迟 <10%
资源加载时长 ~40%
元素渲染延迟 <10%
总计 100%

请注意,这些时间细分仅供参考,而非严格的规定。如果网页上的 LCP 时间始终在 2.5 秒以内,那么相对比例并不重要。但是,如果您在任何“延误”阶段花费了大量不必要的时间那么一直很难达到2.5 秒的目标

下面介绍了一种详细解释 LCP 时间细分的方法:

  • 绝大部分 LCP 时间都应花在加载 HTML 文档和 LCP 源代码上。
  • 如果这两项资源中有一项资源加载,那么在使用 LCP 之前的任何时间都是改进机会
。 <ph type="x-smartling-placeholder">

如何优化各个部分

至此,您已经了解了在充分优化的网页上应如何细分各个 LCP 子部分的时间,接下来可以开始优化自己的网页了。

接下来的四部分将介绍有关如何优化各个部分的建议和最佳做法。这些优化措施按顺序展示,首先是可能产生最大影响的优化措施。

1. 消除资源加载延迟

此步骤的目标是确保 LCP 资源尽早开始加载。虽然从理论上讲,资源最早可以开始加载是在 TTFB 之后立即启动,但实际上,在浏览器实际开始加载资源之前总是要经过一定的延迟。

推荐做法是,您的 LCP 资源应与相应网页加载的第一个资源同时开始加载。或者,换言之,如果开始加载 LCP 资源的时间晚于第一个资源,就表示仍有改进空间。

<ph type="x-smartling-placeholder">
</ph> 显示 LCP 资源在第一个资源之后启动的网络瀑布图,其中显示了改进机会 <ph type="x-smartling-placeholder">
</ph> 在此页面上,LCP 资源在样式值显示完毕后很早就开始加载了 第一个加载的工作表这方面还有改进的空间。

一般来说,有两个因素会影响 LCP 资源的加载速度:

  • 发现资源时。
  • 为资源指定的优先级。

在发现资源时进行优化

为确保您的 LCP 资源尽早开始加载,请务必在浏览器的预加载扫描器在初始 HTML 文档响应中发现该资源。例如,在以下情况下,浏览器可以通过扫描 HTML 文档响应来发现 LCP 资源:

  • LCP 元素为 <img> 元素,其 srcsrcset 属性出现在初始 HTML 标记中。
  • LCP 元素需要 CSS 背景图片,但该图片是通过 HTML 标记中的 <link rel="preload">(或使用 Link 标头)预加载的。
  • LCP 元素是一个需要网页字体才能渲染的文本节点,字体是使用 HTML 标记中的 <link rel="preload">(或使用 Link 标头)加载的。

下面是一些无法通过扫描 HTML 文档响应发现 LCP 资源的示例:

  • LCP 元素是使用 JavaScript 动态添加到网页的 <img>
  • 使用隐藏其 srcsrcset 属性(通常作为 data-srcdata-srcset)的 JavaScript 库延迟加载 LCP 元素。
  • LCP 元素需要 CSS 背景图片。

在每种情况下,浏览器都需要先运行脚本或应用样式表(通常需要等待网络请求完成),然后才能发现 LCP 资源并开始加载它。这从来都不是最佳选择。

为避免不必要的资源加载延迟,您的 LCP 资源应能被 HTML 源代码检测到。如果资源仅从外部 CSS 或 JavaScript 文件引用,则应该为 LCP 资源预加载较高的提取优先级,例如:

<!-- Load the stylesheet that will reference the LCP image. -->
<link rel="stylesheet" href="/path/to/styles.css">

<!-- Preload the LCP image with a high fetchpriority so it starts loading with the stylesheet. -->
<link rel="preload" fetchpriority="high" as="image" href="/path/to/hero-image.webp" type="image/webp">
<ph type="x-smartling-placeholder">

优化为资源指定的优先级

即使可通过 HTML 标记发现 LCP 资源,该资源仍可能无法像第一个资源那样开始加载。如果浏览器预加载扫描器的优先级启发法无法识别相应资源很重要,或者如果它确定其他资源更重要,就会发生这种情况。

例如,如果您对 <img> 元素设置了 loading="lazy",则可以使用 HTML 延迟您的 LCP 图片。使用延迟加载意味着资源在布局确认图片位于视口中后才会加载,因此加载时间可能会比其他情况晚。

<ph type="x-smartling-placeholder">

即使没有延迟加载,浏览器最初也不会以最高优先级加载图片,因为它们不是阻塞渲染的资源。您可以使用 fetchpriority 属性提示浏览器哪些资源最重要:

<img fetchpriority="high" src="/path/to/hero-image.webp">

如果您认为 <img> 元素可能是您网页的 LCP 元素,最好针对该元素设置 fetchpriority="high"。不过,为超过一两张图片设置高优先级会使优先级设置对降低 LCP 没有帮助。

您也可以降低可能在文档响应早期阶段显示但因样式设置而不可见的图片(例如,轮播幻灯片中的图片在启动时不显示)的优先级:

<img fetchpriority="low" src="/path/to/carousel-slide-3.webp">

降低某些资源的优先级可以为需要更多资源的资源提供更多带宽,但请务必谨慎。始终在开发者工具中检查资源优先级,并使用实验室和现场工具测试更改。

优化 LCP 资源优先级和发现时间后,您的网络广告瀑布流应如下所示(LCP 资源与第一项资源同时启动):

<ph type="x-smartling-placeholder">
</ph> 显示 LCP 资源现在与第一个资源同时启动的网络瀑布图 <ph type="x-smartling-placeholder">
</ph> 现在,LCP 资源与样式表同时开始加载。
<ph type="x-smartling-placeholder">

2. 消除元素渲染延迟

此步骤的目标是确保 LCP 元素在其资源加载完成后(无论何时)能够立即呈现。

LCP 元素在其资源完成加载后无法立即呈现的主要原因是呈现由于某种其他原因而被阻止

  • 由于 <head> 中的样式表或同步脚本仍在加载,因此整个网页被阻止呈现。
  • LCP 资源已完成加载,但尚未将 LCP 元素添加到 DOM(正在等待加载一些 JavaScript 代码)。
  • 元素被一些其他代码(例如仍在确定用户应参与的实验的 A/B 测试库)隐藏。
  • 主线程因耗时较长的任务而被阻塞,渲染工作需要等待这些耗时较长的任务完成。

以下各部分介绍了如何解决造成元素渲染延迟不必要的最常见问题。

减少或内嵌阻止渲染的样式表

从 HTML 标记加载的样式表会阻止呈现其后的所有内容,这很好,因为您通常不希望呈现没有样式的 HTML。不过,如果样式表非常大,以致于加载时间远远超过 LCP 资源所花的时间,那么就会阻止 LCP 元素呈现 - 即使其资源加载完毕后也是如此,如下例所示:

<ph type="x-smartling-placeholder">
</ph> 网络广告瀑布流示意图,显示了一个大型 CSS 文件因加载时间比 LCP 资源更长而阻止渲染 LCP 元素 <ph type="x-smartling-placeholder">
</ph> 图片和样式表同时开始加载,但在样式表准备就绪之前无法呈现图片。

要解决此问题,您可以执行以下任一操作:

  • 将样式表内嵌到 HTML 中,以避免产生额外的网络请求;或者
  • 减小样式表的大小。

一般来说,建议仅在样式表较小的情况下内联样式表,因为 HTML 中的内联内容无法从后续网页加载的缓存中受益。如果样式表太大,加载时间比 LCP 资源长,则它就不太可能成为进行内嵌的理想候选对象。

在大多数情况下,确保样式表不会阻止 LCP 元素渲染的最佳方式是缩减其大小,使其小于 LCP 资源。这样可以确保它在大多数访问中不会成为瓶颈。

以下是关于缩减样式表大小的一些建议:

延迟或内嵌阻止渲染的 JavaScript

您几乎完全不需要将同步脚本(没有 asyncdefer 属性的脚本)添加到网页的 <head> 中,这样做几乎总是会对性能产生负面影响。

如果 JavaScript 代码需要在网页加载时尽早运行,则最好将其内嵌在内,以免渲染延迟,等待其他网络请求。不过,与样式表一样,只有在脚本非常小的情况下,您才能内嵌脚本。

错误做法
<head>
  <script src="/path/to/main.js"></script>
</head>
正确做法
<head>
  <script>
    // Inline script contents directly in the HTML.
    // IMPORTANT: only do this for very small scripts.
  </script>
</head>

使用服务器端呈现

服务器端呈现 (SSR) 是在服务器上运行客户端应用逻辑并使用完整 HTML 标记响应 HTML 文档请求的过程。

从优化 LCP 的角度来看,SSR 有两大主要优势:

  • 他人可通过 HTML 源代码发现您的图片资源(如前面的第 1 步中所述)。
  • 您的网页内容无需额外 JavaScript 请求完成即可呈现。

SSR 的主要缺点是需要额外的服务器处理时间,这可能会降低 TTFB。这种权衡通常是值得的,因为服务器的处理时间由您控制,而用户的网络和设备功能则不在您的控制范围内。

与 SSR 类似的选项称为静态网站生成 (SSG) 或预渲染。这是在构建步骤(而不是按需)生成 HTML 页面的过程。如果您的架构可以进行预渲染,通常更适合选择以提升性能。

拆分冗长的任务

即使您采纳了之前的建议,并且您的 JavaScript 代码不会阻塞渲染,也不负责渲染元素,它仍然会延迟 LCP。

出现这种情况的最常见原因是,网页加载了大型 JavaScript 文件,而这些文件需要在浏览器的主线程中进行解析和执行。这意味着,即使您的图片资源已下载完毕,也可能需要等到不相关的脚本执行完毕后才能呈现。

如今,所有浏览器都在主线程上渲染图片,这意味着任何阻塞主线程的行为也可能会导致不必要的元素渲染延迟

3. 缩短资源加载时长

此步骤的目标是减少通过网络将资源的字节传输到用户设备所用的时间。通常,有三种方法可以实现这一目的:

  • 缩减资源的大小。
  • 缩短资源需要移动的距离。
  • 减少网络带宽争用。
  • 完全消除网络时间。

缩减资源大小

网页的 LCP 资源(如果有)将是图片或网页字体。以下指南详细介绍了如何缩减这两者的大小:

缩短资源需要移动的距离

除了缩减资源的大小,您还可以通过让服务器在地理位置上尽可能靠近用户来缩短加载时间。最好的办法是使用内容分发网络 (CDN)。

图片 CDN 尤其有用,因为它们不仅可缩短资源必须传输的距离,而且通常会缩减资源的大小 - 会自动实施之前为您提供的所有大小缩减建议。

<ph type="x-smartling-placeholder">

减少网络带宽争用

即使您减少了资源的大小并缩短了必须移动的距离,如果您同时加载许多其他资源,该资源的加载时间仍然可能较长。此问题称为网络争用

如果您为 LCP 资源指定了较高的 fetchpriority开始尽快加载,则浏览器会尽最大努力阻止优先级较低的资源与之竞争。但是,如果您要加载许多具有较高 fetchpriority 的资源,或者通常要加载大量资源,则可能会影响 LCP 资源的加载速度。

完全消除网络时间

缩短资源加载用时的最佳方法是从流程中完全消除网络。如果您使用高效的缓存控制政策提供资源,则再次请求这些资源的访问者将从缓存中提供这些资源,从而使资源加载时长基本为零!

如果您的 LCP 资源是网页字体,那么除了缩减网页字体大小之外,您还应考虑是否需要在加载网页字体资源时阻止渲染。如果您将 font-display 值设置为 autoblock 以外的任何值,则文本在加载期间始终可见,并且在有其他网络请求时不会屏蔽 LCP。

最后,如果您的 LCP 资源较小,那么可以将资源内嵌为数据网址,同时避免额外的网络请求。不过,使用数据网址需要注意,因为这样会导致资源无法缓存,并且在某些情况下,会因额外的解码成本而导致渲染延迟更长。

4. 缩短加载第一个字节所需的时间

此步骤的目的是尽快提供初始 HTML。这一步最后列出,因为开发者通常对这步的控制力最弱。不过,这也是最重要的步骤之一,因为它会直接影响其后面的每个步骤。在后端传送第一个字节的内容之前,前端不会执行任何操作,因此您可以采取任何提高 TTFB 的措施,也会改善所有其他负载指标。

对于原本速度较快的网站,TTFB 加载速度慢的一个常见原因是访问者通过多次重定向(例如广告或缩短的链接)到达网站。请始终尽量减少访问者必须等待的重定向次数。

另一个常见原因是,缓存的内容无法从 CDN 边缘服务器使用,并且所有请求必须一直定向回源服务器。如果访问者使用独特网址参数进行分析,就可能出现这种情况,即使系统本身并不会产生不同的网页也是如此。

如需关于优化 TTFB 的具体指导,请参阅优化 TTFB 指南

监控 JavaScript 中的 LCP 细分

通过结合使用以下性能 API,您可以使用 JavaScript 获取之前讨论的所有 LCP 子部分的时间信息:

在 JavaScript 中计算这些时间值的好处是,您可以将它们发送给分析提供程序,或将其记录到开发者工具中,以帮助进行调试和优化。

例如,以下屏幕截图使用 User Timing API 中的 performance.measure() 方法向 Chrome 开发者工具“Performance”面板中的“Timings”轨迹添加条形。

<ph type="x-smartling-placeholder">
</ph> Chrome 开发者工具中显示的 LCP 子类别的 User Timing 测量结果 <ph type="x-smartling-placeholder">
</ph> “计时”轨道会显示 LCP 子类别的时间轴。

“计时”轨道中的可视化图表与“网络”和“主线程”轨道并排显示时,会特别有用,因为您可以一目了然地看到页面上在这些时间范围内的其他活动。

除了在计时轨道中直观呈现 LCP 子部分之外,您还可以使用 JavaScript 计算每个子部分占总 LCP 时间的百分比。根据这些信息,您可以判断您的网页是否符合上文所述的建议的百分比细分维度

此屏幕截图显示了一个示例,该示例记录了每个 LCP 子部分的总时间,以及该部分在总 LCP 时间中所占的百分比。

<ph type="x-smartling-placeholder">
</ph> 将 LCP 子类别时间及其 LCP 百分比输出到控制台 <ph type="x-smartling-placeholder">
</ph> LCP 子类别的显示时间和百分比。

这两个可视化图表均使用以下代码创建:

const LCP_SUB_PARTS = [
  'Time to first byte',
  'Resource load delay',
  'Resource load duration',
  'Element render delay',
];

new PerformanceObserver((list) => {
  const lcpEntry = list.getEntries().at(-1);
  const navEntry = performance.getEntriesByType('navigation')[0];
  const lcpResEntry = performance
    .getEntriesByType('resource')
    .filter((e) => e.name === lcpEntry.url)[0];

  // Ignore LCP entries that aren't images to reduce DevTools noise.
  // Comment this line out if you want to include text entries.
  if (!lcpEntry.url) return;

  // Compute the start and end times of each LCP sub-part.
  // WARNING! If your LCP resource is loaded cross-origin, make sure to add
  // the `Timing-Allow-Origin` (TAO) header to get the most accurate results.
  const ttfb = navEntry.responseStart;
  const lcpRequestStart = Math.max(
    ttfb,
    // Prefer `requestStart` (if TOA is set), otherwise use `startTime`.
    lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0
  );
  const lcpResponseEnd = Math.max(
    lcpRequestStart,
    lcpResEntry ? lcpResEntry.responseEnd : 0
  );
  const lcpRenderTime = Math.max(
    lcpResponseEnd,
    // Use LCP startTime (the final LCP time) because there are sometimes
    // slight differences between loadTime/renderTime and startTime
    // due to rounding precision.
    lcpEntry ? lcpEntry.startTime : 0
  );

  // Clear previous measures before making new ones.
  // Note: due to a bug, this doesn't work in Chrome DevTools.
  LCP_SUB_PARTS.forEach((part) => performance.clearMeasures(part));

  // Create measures for each LCP sub-part for easier
  // visualization in the Chrome DevTools Performance panel.
  const lcpSubPartMeasures = [
    performance.measure(LCP_SUB_PARTS[0], {
      start: 0,
      end: ttfb,
    }),
    performance.measure(LCP_SUB_PARTS[1], {
      start: ttfb,
      end: lcpRequestStart,
    }),
    performance.measure(LCP_SUB_PARTS[2], {
      start: lcpRequestStart,
      end: lcpResponseEnd,
    }),
    performance.measure(LCP_SUB_PARTS[3], {
      start: lcpResponseEnd,
      end: lcpRenderTime,
    }),
  ];

  // Log helpful debug information to the console.
  console.log('LCP value: ', lcpRenderTime);
  console.log('LCP element: ', lcpEntry.element, lcpEntry.url);
  console.table(
    lcpSubPartMeasures.map((measure) => ({
      'LCP sub-part': measure.name,
      'Time (ms)': measure.duration,
      '% of LCP': `${
        Math.round((1000 * measure.duration) / lcpRenderTime) / 10
      }%`,
    }))
  );
}).observe({type: 'largest-contentful-paint', buffered: true});

您可以按原样将此代码用于本地调试,也可以修改该代码,将这些数据发送给分析服务提供商,从而更好地了解您的网页上真实用户的 LCP 详情。

使用 Web Vitals 扩展程序监控 LCP 细分数据

Web Vitals 扩展程序在控制台中记录 LCP 时间、LCP 元素和这 4 个子部分,以便您查看此类细分数据。

<ph type="x-smartling-placeholder">
</ph> Web Vitals 扩展程序的控制台日志记录,显示了 LCP 子部分计时 <ph type="x-smartling-placeholder">
</ph> 适用于 Web 的 Console 面板 Vitals 扩展程序会显示 LCP 细分数据。

摘要

LCP 很复杂,其时间会受到多种因素的影响。不过,如果您认为优化 LCP 主要是为了优化 LCP 资源的负载,那么这种方法可以显著简化工作。

概括来讲,优化 LCP 可以分为以下 4 个步骤:

  1. 确保 LCP 资源尽早开始加载。
  2. 确保 LCP 元素可在其资源完成加载后立即渲染。
  3. 在不牺牲质量的情况下,尽可能缩短 LCP 资源的加载时间。
  4. 尽快提供初始 HTML 文档。

如果您能够在网页上执行这些步骤,那么您一定确信自己能为用户提供最佳的加载体验,而且应该会在您的实际 LCP 得分中看到这一点。