您可以预加载自适应图片,这样一来,浏览器便可在渲染 img 标记之前从 srcset 中识别出正确的图片,从而显著加快图片加载速度。
自适应图片概览
假设您在宽度为 300 像素的屏幕上浏览网页,而该网页请求宽度为 1, 500 像素的图片。该网页浪费了您大量移动数据流量,因为您的屏幕无法处理所有这些额外的分辨率。 理想情况下,浏览器会提取比屏幕尺寸略宽的图片版本,例如 325 像素。这样可确保获得高分辨率图片,同时不会浪费数据,并可加快图片加载速度。
借助自适应图片,浏览器可以为不同的设备提取不同的图片资源。如果您不使用图片 CDN,请为每张图片保存多个尺寸,并在 srcset 属性中指定这些尺寸。w 值会告知浏览器每个版本的宽度,以便浏览器能够为任何设备选择合适的版本:
<img src="small.jpg" srcset="small.jpg 500w, medium.jpg 1000w, large.jpg 1500w" alt="…">
预加载概览
预加载可让您告知浏览器您想要尽快加载的关键资源,以便在 HTML 中发现这些资源之前就进行加载。这对于不易发现的资源(例如样式表中包含的字体、背景图片或从脚本加载的资源)尤其有用。
<link rel="preload" as="image" href="important.png" fetchpriority="high">
imagesrcset和imagesizes
<link> 元素使用 imagesrcset 和 imagesizes 属性来预加载自适应图片。将它们与 <link rel="preload"> 一起使用,并使用 <img> 元素中的 srcset 和 sizes 语法。
例如,如果您想预加载使用以下代码指定的自适应图片:
<img src="wolf.jpg" srcset="wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w" sizes="50vw" alt="A rad wolf">
为此,您可以将以下内容添加到 HTML 的 <head> 中:
<link rel="preload" as="image" href="wolf.jpg" imagesrcset="wolf_400px.jpg 400w, wolf_800px.jpg 800w, wolf_1600px.jpg 1600w" imagesizes="50vw" fetchpriority="high">
这会使用与 srcset 和 sizes 相同的资源选择逻辑来发起请求。
使用场景
以下是预加载自适应图片的一些应用场景。
预加载动态注入的自适应图片
假设您要动态加载首页图片作为幻灯片的一部分,并且知道哪张图片将首先显示。在这种情况下,您可能希望尽快显示该图片,而不是等待幻灯片脚本加载该图片。
您可以在具有动态加载的图片库的网站上检查此问题:
- 在新标签页中打开此幻灯片演示。
- 按
Control+Shift+J(在 Mac 上,按Command+Option+J)打开开发者工具。 - 点击网络标签页。
- 在节流下拉列表中,选择快速 3G。
- 取消选中 Disable cache(停用缓存)复选框。
- 重新加载页面。
在此处使用 preload 可让图片提前开始加载,以便在浏览器需要显示图片时,图片已准备就绪。
如需了解预加载带来的差异,请按照第一个示例中的步骤检查同一动态加载的图片库,但预加载第一张图片。
使用 image-set 预加载背景图片
如果您为不同的屏幕密度提供了不同的背景图片,则可以在 CSS 中使用 image-set 语法指定这些图片。然后,浏览器可以根据屏幕的 DPR 选择要显示哪个。
background-image: image-set( "cat.png" 1x, "cat-2x.png" 2x);
CSS 背景图片的问题在于,浏览器只有在下载并处理完网页 <head> 中的所有 CSS 后才会发现它们。
您可以在具有自适应背景图片的示例网站上检查此问题。
借助自适应图片预加载,您可以更快地加载这些图片。
<link rel="preload" as="image" imagesrcset="cat.png 1x, cat-2x.png 2x" fetchpriority="high">
省略 href 属性可确保不支持 <link> 元素上的 imagesrcset 但支持 CSS 中的 image-set 的浏览器下载正确的来源。不过,在这种情况下,他们将无法从预加载中受益。
您可以在自适应背景预加载演示中查看上一个示例在预加载自适应背景图片时的行为。
预加载自适应图片的实际效果
从理论上讲,预加载自适应图片可以加快图片加载速度,但实际效果如何呢?
为了回答这个问题,我创建了两个演示 PWA 商店的副本:一个不预加载图片,另一个预加载部分图片。由于该网站使用 JavaScript 延迟加载图片,因此预加载初始视口中显示的图片可能会带来好处。
- 开始渲染保持不变。
- 速度指数略有提升(273 毫秒,因为图片更快到达,不会占用大量像素区域)。
- Last Painted Hero 显著缩短了 1.2 秒。
预装和 <picture>
Web 性能工作组正在讨论为 srcset 和 sizes 添加等效的预加载,但不会为处理“艺术指导”用例的 <picture> 元素添加等效的预加载。
对于预加载 <picture>,仍有许多技术问题需要解决,但与此同时,也有一些解决方法:
<picture>
<source srcset="small_cat.jpg" media="(max-width: 400px)">
<source srcset="medium_cat.jpg" media="(max-width: 800px)">
<img src="large_cat.jpg">
</picture>
<picture> 元素的图片来源选择逻辑会按顺序检查 <source> 元素的 media 属性,找到第一个匹配的属性,然后使用附加的资源。
由于自适应预加载没有“顺序”或“首次匹配”的概念,因此您需要将断点转换为类似以下内容:
<link rel="preload" href="small_cat.jpg" as="image" media="(max-width: 400px)" fetchpriority="high">
<link rel="preload" href="medium_cat.jpg" as="image" media="(min-width: 400.1px) and (max-width: 800px)" fetchpriority="high">
<link rel="preload" href="large_cat.jpg" as="image" media="(min-width: 800.1px)" fetchpriority="high">
预装和 type
<picture> 元素还支持对第一个 type 进行匹配,以便您提供不同的图片格式,让浏览器可以选择其支持的第一个图片格式。
预加载仅部分支持此使用情形:浏览器应仅下载受支持类型的预加载。因此,您可以通过在预加载中包含此内容来防止浏览器预加载不受支持的 MIME 类型:
<link rel="preload" href="image.avif" type="image/avif" as="image" fetchpriority="high">
不过,与 <picture> 不同,它不会在第一个受支持的类型处停止。因此,如果为多种类型添加了多个预加载,则所有图片都将预加载:
不建议的做法 - 预加载多种类型:
<link rel="preload" href="image.avif" type="image/avif" as="image" fetchpriority="high">
<link rel="preload" href="image.jpg" type="image/jpg" as="image" fetchpriority="high">
改为执行此操作 - 预加载最偏好的类型:
<link rel="preload" href="image.avif" type="image/avif" as="image" fetchpriority="high">
预加载最新格式(在本例中为 AVIF)是一种渐进式增强功能,支持该格式的浏览器会受益,而其他浏览器则不会受益于预加载。
对于图片可在 HTML 中快速发现的网站,我们建议避免预加载,而是让预加载扫描器从 <picture> 和 <source> 元素中提取图片。无论如何,这都是一种最佳实践,尤其是在使用提取优先级来帮助确定相应图片的优先级时,因为这样可以根据浏览器支持情况预加载确切的图片。此外,当图片或网页发生变化时,它还可以避免预加载因主标记而过时。
对 Largest Contentful Paint (LCP) 的影响
由于图片可能是 Largest Contentful Paint (LCP) 候选对象,因此预加载图片可以缩短网站的 LCP。
无论预加载的图片是否具有自适应性,当图片资源在初始标记载荷中不可发现时,预加载效果最佳。与从服务器发送完整标记的网站相比,在客户端上渲染标记的网站上,LCP 改进效果也会更明显。