优化 Largest Contentful Paint

有关如何细分 LCP 并确定关键改进领域的分步指南。

发布时间:2020 年 4 月 30 日

Largest Contentful Paint (LCP) 是三个 Core Web Vitals 指标之一,表示网页主要内容的加载速度。具体而言,LCP 衡量的是从用户发起网页加载到视口中渲染最大图片或文本块所用的时间。

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

LCP 值在 2.5 秒或更短时间内为良好,大于 4.0 秒为较差,介于两者之间的值则需要改进
理想的 LCP 值为 2.5 秒或更短。

许多因素都会影响浏览器加载和呈现网页的速度,其中任何一个因素出现延迟都可能会对 LCP 产生重大影响。

对网页的某个部分进行快速修复,很少能显著缩短 LCP 用时。若要提高 LCP,您必须查看整个加载过程,并确保优化其中的每个步骤。

了解 LCP 指标

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

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

您可以通过在网站上安装实时用户监控 (RUM) 工具,或使用 Chrome 用户体验报告 (CrUX) 来显示基于真实用户的 LCP 数据,后者会从数百万个网站的真实 Chrome 用户收集匿名数据。

使用 Chrome 开发者工具 CrUX LCP 数据

Chrome DevTools 的“Performance”面板会在实时指标视图中,在网页或来源的 CrUX LCP 旁边显示您的本地 LCP 体验。

Chrome DevTools 性能面板中的本地 LCP 和现场 LCP
Chrome DevTools 性能面板中的本地 LCP 和现场 LCP。

通过将现场数据叠加到“效果”面板上,您可以评估网页是否存在任何真实用户 LCP 问题,并调整本地环境设置,以便更好地重现和调试这些问题。

使用 PageSpeed Insights CrUX LCP 数据

PageSpeed Insights 在标记为了解真实用户的体验的顶部部分提供了 CrUX 数据。您可以在底部标有诊断性能问题的部分找到更详细的实验室数据。如果您的网站有 CrUX 数据,请始终先关注真实用户数据。

PageSpeed Insights 中显示的 CrUX 数据
PageSpeed Insights 中显示的 CrUX 数据。

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

  • 此网址移动数据
  • 此网址桌面版数据
  • 整个来源移动流量
  • 整个来源桌面设备数据

您可以在此部分顶部和右上角的控件中进行切换。如果某个网址的数据不足以在网址一级显示,但有源数据,PageSpeed Insights 始终会显示源数据。

在无法获得网址级数据的情况下,PageSpeed Insights 会回退到源级数据
如果 PageSpeed Insights 没有网址级数据,则会显示来源级数据。

整个来源的 LCP 与单个网页的 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 数据采取行动之前,请确保您的 CrUX 数据是针对您的网页(而非整个来源)生成的。

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

Lighthouse LCP 机会和诊断
Lighthouse 诊断和有关如何缩短 LCP 时间的建议。

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

Lighthouse 中的 LCP 阶段
Lighthouse 对 LCP 元素的细分。

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

LCP 细分

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

本部分介绍了如何将 LCP 细分为其最重要的子部分,然后介绍了有关如何优化每个部分的具体建议和最佳实践。

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

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

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

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

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

网络广告瀑布流,其中突出显示了 HTML 和 LCP 资源
一个瀑布图,显示了网页 HTML 的加载时间和 LCP 所需的资源。

对于经过良好优化的页面,您希望 LCP 资源请求尽早开始加载,并且希望 LCP 元素在 LCP 资源加载完成后尽快渲染。为了直观地了解特定网页是否遵循此原则,您可以将总 LCP 时间细分为以下子部分:

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

每个网页的 LCP 都由这四个子类别组成。它们之间没有间隔或重叠,并且它们的总和就是完整的 LCP 时间。

LCP 细分数据,其中显示了四个子类别
同一广告瀑布流图表,在时间轴上叠加了四个 LCP 子类别。

每个网页的 LCP 值都可以细分为这四个子部分。它们之间没有重叠或间隔。它们的总和就是完整的 LCP 时间。

优化 LCP 时,尝试单独优化这些子部分会很有帮助。但请务必注意,您需要优化所有这些方面。在某些情况下,对某个部分应用的优化不会改善 LCP,只会将节省的时间转移到另一个部分。

例如,在前面的网络广告瀑布流中,如果您通过更高压缩率或改用更优化的格式(例如 AVIF 或 WebP)来缩减图片的文件大小,这会缩短资源加载时长,但实际上不会改善 LCP,因为时间只会转移到元素呈现延迟子部分:

与上文中显示的 LCP 细分相同,其中资源加载时长子类别缩短,但总体 LCP 时间保持不变。
缩短资源加载时长会增加元素渲染延迟,而不会降低 LCP。

出现这种情况的原因是,在该页面上,LCP 元素会一直处于隐藏状态,直到 JavaScript 代码加载完毕,然后所有要素才会同时显示出来。

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

最佳分段时间

为了优化 LCP 的每个子部分,请务必了解经过充分优化的网页上这些子部分的理想细分。

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

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

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

考虑 LCP 时间细分的一种好方法是:

  • 绝大多数 LCP 时间应花在加载 HTML 文档和 LCP 来源上。
  • 如果这两个资源在 LCP 之前有任何一个加载,就有机会改进

如何优化各个部分

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

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

1. 消除资源加载延迟

此步骤的目标是确保 LCP 资源尽早开始加载。虽然在理论上,资源最早可在 TTFB 后立即开始加载,但在实践中,浏览器始终会在实际开始加载资源之前延迟一段时间。

一般来说,LCP 资源应与该网页加载的第一个资源同时开始加载。换句话说,如果 LCP 资源的加载时间晚于第一个资源,则说明有改进的空间。

网络瀑布流图,显示 LCP 资源在第一个资源之后开始加载,并显示有改进空间
在本页面上,LCP 资源会在最先加载的样式表之后开始加载。这方面仍有改进空间。

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

  • 发现资源的时间。
  • 资源的优先级。

在发现资源时进行优化

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

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

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

  • LCP 元素是一种 <img>,使用 JavaScript 动态添加到网页中。
  • LCP 元素会使用会隐藏其 srcsrcset 属性(通常为 data-srcdata-srcset)的 JavaScript 库进行延迟加载。
  • 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">

优化为资源指定的优先级

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

例如,如果您在 <img> 元素上设置 loading="lazy",则可以使用 HTML 延迟 LCP 图片。使用延迟加载意味着,只有在布局确认图片位于视口内后,系统才会加载资源,因此加载时间可能会比以往晚一些。

即使没有延迟加载,浏览器最初也不会以最高优先级加载图片,因为它们不是阻塞渲染的资源。您可以为可能受益于更高优先级的资源使用 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">

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

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

网络瀑布图,显示 LCP 资源现在与第一个资源同时开始加载
LCP 资源现在会与样式表同时开始加载。

2. 消除元素渲染延迟

本步骤的目标是确保 LCP 元素可在其资源完成加载(无论何时)后立即渲染。

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

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

以下部分介绍了如何解决导致不必要元素呈现延迟的最常见原因。

减少阻塞渲染的样式表或将其内嵌

从 HTML 标记加载的样式表会阻止呈现其后的所有内容,这很好,因为您通常不希望呈现没有样式的 HTML。不过,如果样式表太大,其加载时间比 LCP 资源明显要长,则会阻止 LCP 元素渲染,即使其资源已完成加载也是如此,如以下示例所示:

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

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

  • 将样式表内嵌到 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 尤其有用,因为它们不仅可以缩短资源传输的距离,通常还可以缩减资源的大小,从而自动为您实现上述所有缩减大小建议。

减少网络带宽争用

即使您缩减了资源的大小和传输距离,如果您同时加载许多其他资源,资源仍可能需要很长时间才能加载完毕。此问题称为网络争用

如果您为 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 开发者工具“性能”面板中的“时间”轨道添加条状图。

Chrome 开发者工具中显示的 LCP 子类别的 User Timing 测量结果
“计时”轨迹显示 LCP 子类别的时间轴。

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

除了在时间轨迹中直观呈现 LCP 子部分之外,您还可以使用 JavaScript 计算每个子部分在总 LCP 时间中的百分比。有了这些信息,您就可以确定自己的网页是否符合前面介绍的建议的百分比细分

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

将 LCP 子类别时间及其 LCP 百分比输出到控制台
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 详情。

摘要

LCP 非常复杂,其时间可能会受到多种因素的影响。不过,如果您认为优化 LCP 主要是为了优化 LCP 资源的加载,那么事情就会变得简单得多。

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

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

如果您能够在自己的网页上按照这些步骤操作,则可以放心地为用户提供最佳加载体验,并且您应该会在实际 LCP 得分中看到这一点。