
通过优化图像加载来修复您网站的最大内容绘制 (Largest Contentful Paint)
图片占大多数网站的很大一部分。它们通常也是您页面上首先出现的最大元素,因此是最大内容绘制 (LCP) 元素——这是 Google 核心网页指标中的一个指标。当图片加载缓慢时,它们会延长您的 LCP 时间。这会损害您的核心网页指标得分和整体用户体验。让我们看看如何让网页上的图片加载得更快。
简介
当您将图片添加到网站时,幕后发生的事情比您想象的要多。从基础开始,将图片添加到页面上的最简单方法是使用 HTML 的<img>
元素。
<img src="image.jpg" alt="Description of the image" />
您也可以使用 CSS 背景图片来添加图片,这些图片仍然是LCP 的候选者。
.container {
background-image: url("image.jpg");
}
有些开发者会改用 JavaScript 来加载图片。这会延迟浏览器开始下载图片的时间,因为 JavaScript 需要先运行。
// Don't load images like this unless you have a good reason
const img = new Image();
img.src = "image.jpg";
document.querySelector(".container").appendChild(img);
事实上,当您的 JavaScript 文件请求其他 JavaScript 文件,然后这些文件又请求图片时,JavaScript 方法可能会更糟。这被称为请求链,将在本文后面解释。
要理解图片加载,我们使用网络请求瀑布图。这些图显示了您页面上所有网络请求的时间。像DebugBear 这样的现代性能测试工具可以为您生成这些瀑布图,甚至可以识别您页面上的 LCP 元素,正如上一个屏幕截图中 LCP 徽章所示。
图片在网页上的加载方式
当图片在网页上加载时会发生什么?理解这个过程有助于解释为什么某些优化技术有效。
当浏览器在加载的 HTML 中找到图片时,浏览器会
- 发起网络请求以下载图片:这就像下载任何其他资源一样,例如 CSS 或 JavaScript。
- 为该请求分配优先级(稍后详述):这决定了图片相对于其他资源的下载时间。
- 到达后解码图片数据:这是将原始图片数据转换为可在屏幕上显示的像素的过程。
- 渲染页面上的图片:浏览器根据页面布局定位并显示图片。
与某些资源(如 CSS)不同,图片下载不会阻止页面其余部分的加载。
图片加载如何影响 LCP
LCP 由子部分组成。每个子部分都会影响 LCP 的总体得分。子部分越慢,LCP 得分越慢。下图显示了 DebugBear 的真实用户监控仪表板的一部分,该仪表板已为真实页面视图识别出 LCP 子部分。
了解每个子部分是理解如何提高 LCP 分数的关键,因此让我们详细看看这些子部分。
首字节时间(TTFB)
这是服务器开始响应主 HTML 文档所需的时间。如果出现以下情况,这可能会特别慢:
- 服务器和用户之间存在较大的地理距离。
- 缓存头不正确或网站使用了未经优化的缓存策略。
此屏幕截图显示了特定请求的网络时间信息。有趣的是,TTFB 比下载本身花费的时间更长!事实上,突出显示的许多其他资源的 TTFB 也比下载本身花费的时间更长!
资源加载延迟
这是浏览器发现图片并请求图片所需的时间。这可能会很慢,如果:
- 图片位于请求链中,其中资源必须在图片开始下载之前加载。
- 图片是延迟加载的,这会延迟下载,直到图片接近或在视口内。
- 图片是使用 JavaScript 插入到 DOM 中的——即使该 JavaScript 内联在 HTML 中。这是因为浏览器在发现图片之前必须解析和执行 JavaScript。
资源下载时间
这是图片下载所需的时间,很可能这是大多数人想到“加载缓慢的图片”时所想到的。这可能会很慢,如果:
- 图片很大且未优化。
- 屏幕外的图片或其他非关键资源同时下载,导致网络争用。
下图显示了一系列 JavaScript 文件,其中下载时间远远超过了 TTFB。DebugBear 中的请求瀑布图显示了实际内容下载发生在水平蓝色条内。较深的蓝色表示内容下载正在进行中。
资源渲染延迟
这是浏览器解码图片数据并将其渲染到页面所需的时间。这可能会很慢,如果:
- 图片使用了高度压缩的格式,解码需要更多时间。
- 渲染阻塞资源仍在下载中,这可能会延迟图片的渲染。
- 主线程被阻塞,无法将图片渲染到页面。
- 图片是使用
<link rel="preload">
元素加载的,但使用该图片的页面元素尚未创建。
现代图片格式和响应式图片
现代图片格式有助于减小图片文件大小,同时保持质量。使用现代图片格式可能对 LCP 的**资源下载时间**子部分产生积极影响。推荐的现代格式是:
您可以使用Squoosh Web 应用将图片转换为这些格式。以下是如何为浏览器提供不同格式供其选择的方法:
<picture>
<source srcset="image.avif" type="image/avif" />
<source srcset="image.webp" type="image/webp" />
<img
src="image.jpg"
alt="Description of the image"
width="1200"
height="800" />
</picture>
下图显示了请求瀑布图中的 LCP 资源。虽然 TTFB 很重要,但与整个 3 秒的图片内容下载时间相比,它就不那么显著了。考虑到该实验室测试是在节流连接上运行的,并且考虑到该图片大小为 1MB,这就说得通了。
将 1MB 图片放入 Squoosh,并将其转换为 AVIF @ 80% 质量,可节省 95%,文件大小仅为 46KB。这对内容下载时间产生了积极影响。
使用现代图片格式时,考虑浏览器支持非常重要。您还可以考虑配置您的服务器,根据浏览器的Accept 标头来提供正确的格式。
响应式图片可帮助您为每种屏幕提供正确大小的图片。这可以节省带宽和处理时间。
<img
src="small.jpg"
srcset="small.jpg 300w, medium.jpg 600w, large.jpg 900w"
sizes="(max-width: 500px) 300px,
(max-width: 900px) 600px,
900px"
alt="Description of the image" />
该示例使用<img>
元素(而不是<picture>
元素)以及 `srcset` 和 `sizes` 属性,为不同视口宽度提供小、中、大图片候选。
- 小屏幕上的小图片(小于 500px 宽)。
- 中等屏幕上的中等图片(500px 到 900px 宽)。
- 大屏幕上的大图片(大于 900px 宽)。
这样,您就不会在小屏幕上浪费大图片的带宽。作为实际示例,该网站在移动视口上仍需要很长时间才能下载 LCP 图片,高达 2.26MB。
进一步调查后发现,该图片的尺寸为**1920 × 1080**。在将此图片优化为使用现代图片格式后,开发此网站的开发人员可以生成适用于不同视口尺寸的图片版本。
请求链如何影响 LCP
有时,由于请求链,图片会比应有的晚出现。当一个或多个资源(主 HTML 之外)必须先加载,然后另一个请求才能开始时,就会发生请求链。
例如,如果您的 JavaScript 加载了一张图片,从高层次来看,浏览器需要:
- 下载 HTML。
- 下载 JavaScript:取决于 JavaScript 的加载方式,这也会阻塞页面渲染。
- 执行 JavaScript:JavaScript 有解析和执行的成本,这在低端设备上通常会加剧。
- 开始下载图片。
这会形成一个延迟图片加载的链。您可以通过以下方式帮助打破这个链:
- 在 HTML 中直接使用常规的
<img>
元素。 - 使用
<link rel="preload">
元素更早地下载图片。
preload
提示告诉浏览器尽快下载资源,并放置在 HTML 的 head 中。
<link rel="preload" as="image" href="image.jpg" />
在此示例中,DebugBear 识别出 LCP 图片是链的一部分,并提供了一个实验来测试修复。
该实验会自动将 LCP 图片的请求链(包括 LCP 图片本身)预加载到主 HTML 文档中。运行实验后,可以查看之前和之后的比较。
上一个屏幕截图显示:
- LCP 请求链中的 CSS 资源现已预加载。
- LCP 图片本身现已预加载。
下方的 LCP 分数对比图证实了改进。
为关键图片使用 fetchpriority=high
浏览器为网络请求分配不同的优先级。这决定了当资源争用带宽时,它们的下载顺序。您可以使用fetchpriority
属性来提高 LCP 图片的优先级。
<img src="image.jpg" alt="Description of the image" fetchpriority="high" />
这会告诉浏览器优先下载图片,而不是其他资源。您还可以将 `fetchpriority` 与rel="preload"
属性结合使用。
<link
rel="preload"
href="/background-image.avif"
as="image"
fetchpriority="high" />
当 LCP 是背景图片,否则将在页面加载后期(在 CSS 下载和解析之后)才能发现时,这会特别有用。
此示例显示了 Discord 的一项改进,其中 LCP 图片的**整个**请求链被预加载,并标记为 `fetchpriority="high"`,这有助于提高 LCP 时间。
分数差异
请求瀑布图差异
上一个屏幕截图显示了 Discord 的 LCP 图片是如何更早下载的。
FP=HIGH
徽章确认指定了高 `fetchpriority`,因此 LCP 资源现在保持高优先级,而之前,LCP 图片最初是低优先级。
DebugBear 请求瀑布图视图中出现的细红线表示了其优先级已更改的资源。如果浏览器发现需要更改优先级(例如从`low`优先级更改为`high`优先级)来得太晚,您可以应用 `fetchpriority="high"` 到适用的资源来帮助浏览器。
延迟加载图片
并非所有图片都需要立即加载。视口下方的图片可以稍后加载,从而为更重要的资源节省带宽。以下是如何延迟加载图片:
<img loading="lazy" src="image.jpg" alt="Description of the image" />
考虑一个有 10 张图片的网页,其中只有第一张图片(LCP 元素)在初始视口中可见。在这种情况下,延迟加载剩余的 9 张图片可以帮助提高第一张图片的加载速度。当您延迟加载折叠以下的图片时,您会:
- 减少带宽竞争。当您释放带宽时,LCP 图片有时可以加载得更快。
- 让浏览器优先加载重要资源。
- 如果用户从不向下滚动,则节省用户数据。
此示例显示了同一网站的两个不同瀑布图,这些示例试图显示资源争用对 LCP 图片的影响。
瀑布图 1 显示了一张大 LCP 图片,该图片下载耗时很长,并且似乎与页面上的其他图片资源争夺带宽。
瀑布图 2 显示了同一张大 LCP 图片,但这次,DebugBear 的请求阻止功能被用来阻止非主要的 LCP 图片的其他图片资源。这是作为测试进行的,以显示带宽争用如何影响资源下载时间。
仔细观察,`RB_8220-Large-1.png` 图片的实际数据下载(深蓝色块)在第二个瀑布图中更加集中。要理解这对时间造成的重大影响,请查看瀑布图比较视图。在 LCP 图片无需争夺带宽的测试运行中,图片下载时间缩短了一半以上!
总结
图片占大多数网站的很大一部分,并可能对您的 LCP 分数产生重大影响。以下是优化 LCP 图片的摘要:
- 使用 WebP 和 AVIF 等现代图片格式。
- 提供响应式图片以节省带宽。
- 使用 `preload` 和 `fetchpriority` 来优先处理关键图片。
- 延迟加载视口下方的图片以减少网络争用。
- 避免会延迟图片加载的请求链。
本文由DebugBear赞助。DebugBear 帮助团队优化 Web 性能和核心网页指标,提供速度洞察和持续监控,以实现更快的网站。