图片是大多数网站的重要组成部分。它们通常也是页面上首先显示的最大元素,因此也是最大内容绘制 (LCP)元素——这是 Google核心网络指标 (Core Web Vitals)中的一个指标。图片加载缓慢会延长 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 文件又请求图像时,JavaScript 的处理方式可能会更加糟糕。这种情况被称为请求链,本文稍后将对此进行解释。
为了理解图片加载过程,我们使用了网络请求瀑布图。这些瀑布图显示了页面上所有网络请求的时序。像DebugBear这样的现代性能测试工具可以为您生成这些瀑布图,甚至可以识别页面上的 LCP 元素,如上图所示的 LCP 标记。
网页上图片如何加载
当图片加载到网页上时会发生什么?了解这个过程有助于解释某些优化技术为何有效。
当浏览器在 HTML 中找到正在加载的图像时,浏览器会:
- 发出网络请求下载图像:这就像下载任何其他资源一样,例如 CSS 或 JavaScript。
- 为该请求分配优先级(稍后会详细介绍):这决定了与其他资源相比图像何时下载。
- 图像数据到达后进行解码:这是将原始图像数据转换为可在屏幕上显示的像素的过程。
- 在页面上呈现图像:浏览器根据页面布局定位并显示图像。
与某些资源(例如 CSS)不同,图像下载不会阻止页面其余部分的加载。
图像加载如何影响 LCP
LCP 由多个子部分组成。每个子部分都会对整体 LCP 得分产生影响。子部分越慢,LCP 得分就越慢。以下屏幕截图显示了 DebugBear真实用户监控仪表板的一部分,其中已识别出真实页面浏览的 LCP 子部分。
了解每个子部分是理解如何提高 LCP 分数的关键,因此让我们详细了解一下每个子部分。
第一个字节的时间(TTFB)
这是服务器开始响应主 HTML 文档所需的时间。在以下情况下,响应速度可能会非常慢:
- 服务器和用户之间的地理距离很远。
- 存在不正确的缓存标头或网站使用未优化的缓存策略。
这张截图展示了特定请求的网络时间信息。有趣的是,TTFB 比下载本身还要长!事实上,其他高亮显示的资源的 TTFB 也比下载本身要长!
资源加载延迟
这是浏览器发现图片并请求图片所需的时间。在以下情况下,请求速度可能会很慢:
- 图像位于请求链中,必须先加载资源,然后才能开始下载图像。
- 图像是延迟加载的,它会延迟下载,直到图像接近或在视口中。
- 即使 JavaScript 已内联在 HTML 中,图像也会通过 JavaScript 插入到 DOM 中。这是因为浏览器的前瞻解析器必须先解析并执行 JavaScript,然后才能发现图像。
资源下载时间
这是图片下载所需的时间,我们大多数人想到“图片加载缓慢”时,可能就是这么想的。如果出现以下情况,图片加载速度可能会很慢:
- 图像很大且未优化。
- 屏幕外图像或其他非关键资源同时下载,导致网络争用。
下图展示了一组 JavaScript 文件,其下载时间远远超过了 TTFB。DebugBear 中的请求瀑布图指示了水平蓝色条内实际内容下载的位置。深蓝色表示内容下载正在进行中。
资源渲染延迟
这是浏览器解码图像数据并将其渲染到页面上所需的时间。在以下情况下,渲染速度可能会很慢:
- 该图像采用高度压缩的格式,解码需要更多时间。
- 渲染阻塞资源仍在下载,这可能会延迟图像渲染。
- 主线程被阻塞,无法将图像渲染到页面。
- 使用元素加载了图像
<link rel="preload">
,但使用该图像的页面元素尚未创建
现代图像格式和响应式图像
现代图像格式有助于在保持质量的同时减小图像文件大小。使用现代图像格式可以对 LCP 的**“资源下载时间**”子部分产生积极影响。推荐的现代格式如下:
您可以使用Squoosh网页应用将图片转换为这些格式。以下是如何为浏览器提供不同格式供选择:
<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 大小,所以 TTFB 就显得合情合理了。
将 1MB 的图片导入 Squoosh,并以 80% 的画质将其转换为 AVIF 格式,可节省 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"
/>
该示例使用<picture>
元素来指定适用于各种尺寸的图像:
- 小屏幕上的小图像(宽度小于 500px)。
- 中等屏幕上的中等图像(宽度为 500px 到 900px)。
- 大屏幕上的大图像(宽度超过 900px)。
这样,您就不会在小屏幕上浪费大图像的带宽。举个实际的例子,即使在移动端,该网站下载一张 2.26MB 的 LCP 图像也需要很长时间。
经过进一步调查,发现该图像的尺寸为1920 × 1080。在优化该图像以使用现代图像格式后,该网站的开发人员可以生成适合不同视口尺寸的不同版本的图像。
请求链如何影响 LCP
有时,由于请求链的存在,图片的显示会比预期的要晚。当一个或多个资源(主 HTML 之外的资源)必须先加载,然后才能启动另一个请求时,就会发生请求链:
例如,如果您的 JavaScript 加载图像,从高层次来看,浏览器必须:
- 下载 HTML。
- 下载 JavaScript:根据 JavaScript 的加载方式,这也会阻止页面渲染。
- 执行 JavaScript:JavaScript 的解析和执行需要成本,这在低端设备上通常会加剧。
- 开始下载图像。
这会形成一个延迟图片加载的链条。您可以通过以下方式打破这个链条:
<img>
直接在 HTML 中使用常规元素。- 使用
<link rel="preload">
元素提前下载图像。
预加载提示告诉浏览器尽快下载资源,并放置在 HTML 的头部:
<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
对关键图像进行优先排序。 - 延迟加载折叠下方的图像以减少网络争用。
- 避免延迟图像加载的请求链。