图片通常是网络上体量最大且最常见的资源。因此,优化图片可以显著提升网站的性能。在大多数情况下,优化图片意味着通过发送更少的字节来缩短网络传输时间,但您也可以通过提供适合用户设备的尺寸的图片来优化向用户发送的字节数。
您可以使用 <img>
或 <picture>
元素或 CSS background-image
属性将图片添加到网页中。
图片大小
在使用图片资源时,您可以执行的第一个优化是按正确的尺寸显示图片。在本例中,“尺寸”一词是指图片的尺寸。假设没有其他变量,在 500 x 500 像素的容器中显示的图片的最佳尺寸为 500 x 500 像素。例如,使用 1000 像素的正方形图片意味着图片的大小是所需大小的两倍。
不过,选择合适的图片大小涉及许多变量,因此在每种情况下选择合适的图片大小都是一项相当复杂的任务。2010 年,iPhone 4 发布时,其屏幕分辨率 (640x960) 是 iPhone 3 (320x480) 的两倍。不过,iPhone 4 屏幕的物理尺寸与 iPhone 3 大致相同。
如果以更高的分辨率显示所有内容,文本和图片会明显变小,确切地说,会变小到原来的一半。而是将 1 个像素变成 2 个设备像素。这称为设备像素比 (DPR)。iPhone 4 及之后发布的许多 iPhone 型号的 DPR 均为 2。
再来看一下前面的示例,如果设备的 DPR 为 2,并且图片显示在 500 x 500 像素的容器中,那么 1000 像素的方形图片(称为内在尺寸)现在是最佳尺寸。同样,如果设备的 DPR 为 3,则 1500 像素的正方形图片是最佳尺寸。
srcset
<img>
元素支持 srcset
属性,您可以使用该属性指定浏览器可能会使用的可能图片来源的列表。指定的每个图片来源都必须包含图片网址以及宽度或像素密度描述符。
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
srcset="/image-500.jpg 1x, /image-1000.jpg 2x, /image-1500.jpg 3x"
>
上面的 HTML 代码段使用像素密度描述符提示浏览器在 DPR 为 1 的设备上使用 image-500.png
,在 DPR 为 2 的设备上使用 image-1000.jpg
,在 DPR 为 3 的设备上使用 image-1500.jpg
。
虽然这一切看起来很简单,但在为给定网页选择最佳图片时,屏幕的 DPR 并非唯一要考虑的因素。页面的布局也是一个需要考虑的因素。
sizes
只有在所有视口中以相同的 CSS 像素大小显示图片时,上一个解决方案才有效。在许多情况下,网页的布局(以及容器的大小)会因用户的设备而异。
借助 sizes
属性,您可以指定一组来源大小,其中每个来源大小都由媒体条件和值组成。sizes
属性描述了图片的预期显示大小(以 CSS 像素为单位)。与 srcset
宽度描述符结合使用时,浏览器可以选择最适合用户设备的图片来源。
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
srcset="/image-500.jpg 500w, /image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
在上面的 HTML 代码段中,srcset
属性指定了浏览器可以选择的候选图片列表,各个图片之间以英文逗号分隔。列表中的每个候选图片都由图片的网址和表示图片内在宽度的语法组成。图片的固有尺寸是指其尺寸。例如,描述符 1000w
表示图片的内在宽度为 1000 像素。
浏览器会使用这些信息评估 sizes
属性中的媒体条件,在本例中,浏览器会收到以下指示:如果设备的视口宽度超过 768 像素,则将图片的宽度显示为 500 像素。在较小的设备上,图片以 100vw
(或整个视口宽度)的宽度显示。
然后,浏览器可以将此信息与 srcset
图片来源列表结合使用,以查找最佳图片。例如,如果用户使用的是屏幕宽度为 320 像素且 DPR 为 3 的移动设备,则图片将显示在 320 CSS pixels x 3 DPR = 960 device pixels
处。在此示例中,最接近的图片是 image-1000.jpg
,其固有宽度为 1000 像素 (1000w
)。
文件格式
浏览器支持多种不同的图片文件格式。WebP 和 AVIF 等新型图片格式的压缩效果可能优于 PNG 或 JPEG,从而缩减图片文件大小,从而缩短下载时间。通过以现代格式提供图片,您可以缩短资源的加载时间,这可能会降低 Largest Contentful Paint (LCP)。
WebP 是一种广泛受支持的格式,适用于所有新型浏览器。WebP 通常比 JPEG、PNG 或 GIF 具有更好的压缩效果,同时提供有损压缩和无损压缩。WebP 还支持 Alpha 通道透明度,即使使用有损压缩也是如此,而 JPEG 编解码器不提供此功能。
AVIF 是一种较新的图片格式,虽然其受支持的范围不如 WebP 广泛,但在各浏览器中还是获得了相当不错的支持。AVIF 同时支持有损和无损压缩,在某些情况下,测试表明与 JPEG 相比,可节省超过 50% 的空间。AVIF 还提供广色域 (WCG) 和高动态范围 (HDR) 功能。
压缩
图片有两种压缩方式:
有损压缩的工作原理是通过量化来降低图片准确性,并且可能会使用色度子采样丢弃额外的颜色信息。对包含大量噪点和颜色的高密度图片(通常是包含类似内容的照片或图像),有损压缩最为有效。这是因为,在如此精细的图片中,有损压缩产生的伪影不太容易被察觉。不过,对于包含锐利边缘(例如线条艺术、类似的鲜明细节)或文字的图片,有损压缩的效果可能不太理想。有损压缩可应用于 JPEG、WebP 和 AVIF 图片。
无损压缩会压缩图片,而不会丢失数据,从而缩减文件大小。无损压缩会根据像素与相邻像素的差异来描述像素。无损压缩适用于 GIF、PNG、WebP 和 AVIF 图片格式。
您可以使用 Squoosh、ImageOptim 或图片优化服务压缩图片。压缩时,没有适用于所有情况的通用设置。建议的方法是尝试不同的压缩级别,直到在图片质量和文件大小之间找到合适的折衷。某些高级图片优化服务可以自动为您执行此操作,但可能并不适合所有用户。
<picture>
元素
借助 <picture>
元素,您可以更灵活地指定多个候选图片:
<picture>
<source type="image/avif" srcset="image.avif">
<source type="image/webp" srcset="image.webp">
<img
alt="An image"
width="500"
height="500"
src="/image.jpg"
>
</picture>
在 <picture>
元素中使用 <source>
元素时,您可以添加对 AVIF 和 WebP 图片的支持,但如果浏览器不支持新型格式,则会回退到更兼容的旧版图片格式。采用这种方法时,浏览器会选择第一个匹配的指定 <source>
元素。如果它可以以该格式呈现图片,则会使用该图片。否则,浏览器会移至下一个指定的 <source>
元素。在上面的 HTML 代码段中,AVIF 格式优先于 WebP 格式,如果系统不支持 AVIF 或 WebP,则会回退到 JPEG 格式。
<picture>
元素需要嵌套在其中的 <img>
元素。alt
、width
和 height
属性在 <img>
上定义,无论选择哪个 <source>
,都会使用这些属性。
<source>
元素还支持 media
、srcset
和 sizes
属性。与前面的 <img>
示例类似,这些指示会告知浏览器在不同的视口中选择哪张图片。
<picture>
<source
media="(min-resolution: 1.5x)"
srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
media
属性采用媒体条件。在前面的示例中,设备的 DPR 用作媒体条件。任何 DPR 大于或等于 1.5 的设备都将使用第一个 <source>
元素。<source>
元素会告知浏览器,在视口宽度大于 768 像素的设备上,所选的候选图片的宽度为 500 像素。在较小的设备上,此项会占据整个视口宽度。通过组合使用 media
和 srcset
属性,您可以更精细地控制要使用的图片。
下表对此进行了说明,其中评估了多个视口宽度和设备像素比率:
视口宽度(像素) | 1 DPR | 1.5 DPR | 2 DPR | 3 DPR |
---|---|---|---|---|
320 | 500.jpg | 500.jpg | 500.jpg | 1000.jpg |
480 | 500.jpg | 500.jpg | 1000.jpg | 1500.jpg |
560 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1024 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1920 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
DPR 为 1 的设备会下载 image-500.jpg
图片,包括大多数桌面用户(他们会以宽 500 像素的外部尺寸查看图片)。另一方面,DPR 为 3 的移动用户下载的 image-1500.jpg
可能更大,与 DPR 为 3 的桌面设备上使用的图片相同。
<picture>
<source
media="(min-width: 561px) and (min-resolution: 1.5x)"
srcset="/image-1000.jpg 1000w, /image-1500.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<source
media="(max-width: 560px) and (min-resolution: 1.5x)"
srcset="/image-1000-sm.jpg 1000w, /image-1500-sm.jpg 1500w"
sizes="(min-width: 768px) 500px, 100vw"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
在此示例中,<picture>
元素已调整为包含额外的 <source>
元素,以便针对 DPR 较高的宽屏设备使用不同的图片:
视口宽度(像素) | 1 DPR | 1.5 DPR | 2 DPR | 3 DPR |
---|---|---|---|---|
320 | 500.jpg | 500.jpg | 1000-sm.jpg | 1000-sm.jpg |
480 | 500.jpg | 500.jpg | 1000-sm.jpg | 1500-sm.jpg |
560 | 500.jpg | 1000-sm.jpg | 1000-sm.jpg | 1500-sm.jpg |
1024 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
1920 | 500.jpg | 1000.jpg | 1000.jpg | 1500.jpg |
通过这个额外的查询,您可以看到 image-1000-sm.jpg
和 image-1500-sm.jpg
会显示在小视口中。由于在这种尺寸和密度下压缩伪影不太明显,同时也不会影响桌面设备上的图片质量,因此您可以利用这些额外信息进一步压缩图片。
或者,您也可以通过调整 srcset
和 media
属性,避免在小视口中提交大图片:
<picture>
<source
media="(min-width: 561px)"
srcset="/image-500.jpg, /image-1000.jpg 2x, /image-1500.jpg 3x"
>
<source
media="(max-width: 560px)"
srcset="/image-500.jpg 1x, /image-1000.jpg 2x"
>
<img
alt="An image"
width="500"
height="500"
src="/image-500.jpg"
>
</picture>
在上面的 HTML 代码段中,宽度描述符已被移除,取而代之的是设备像素比描述符。在移动设备上投放的图片仅限 /image-500.jpg
或 /image-1000.jpg
,即使在 DPR 为 3 的设备上也是如此。
如何管理复杂性
使用自适应图片时,您可能会发现每张图片有多种不同的尺寸变体和格式。在上面的示例中,系统会使用每种尺寸的变体,但不包括 AVIF 和 WebP。您应该有多少个变体?与许多工程问题一样,答案往往是“取决于”。
虽然您可能很想提供尽可能多的变体以提供最合适的图片,但每增加一个图片变体都会产生成本,并且会降低浏览器缓存的使用效率。只有一个变体时,每个用户都会收到相同的图片,因此可以非常高效地进行缓存。
另一方面,如果有许多变体,则每个变体都需要另一个缓存条目。如果变体的缓存条目已过期,并且需要从源服务器重新提取图片,则服务器费用可能会增加,并且性能可能会下降。
除此之外,HTML 文档的大小会随着每个变体的增加而增加。您可能会发现,每个图片都需要传输数千字节的 HTML 代码。
根据 Accept
请求标头提供图片
Accept
HTTP 请求标头会告知服务器用户的浏览器支持哪些内容类型。您的服务器可以使用此信息来提供最佳图片格式,而无需向 HTML 响应添加额外的字节。
if (request.headers.accept) {
if (request.headers.accept.includes('image/avif')) {
return reply.from('image.avif');
} else if (request.headers.accept.includes('image/webp')) {
return reply.from('image.webp');
}
}
return reply.from('image.jpg');
上述 HTML 代码段是该代码的简化版本,您可以将其添加到服务器的 JavaScript 后端,以选择和提供最佳图片格式。如果请求 Accept
标头包含 image/avif
,则系统会提供 AVIF 图片。否则,如果 Accept
标头包含 image/webp
,则会提供 WebP 图片。如果这两种情况都不是,则系统会提供 JPEG 图片。
您可以在几乎所有类型的网络服务器中根据 Accept
请求标头的内容修改响应,例如,您可以使用 mod_rewrite
基于 Accept
标头在 Apache 服务器上重写图片请求。
这与您在图片内容分发网络 (CDN) 上看到的行为类似。图片 CDN 是优化图片和根据用户的设备和浏览器发送最佳格式的绝佳解决方案。
关键在于找到平衡点,生成合理数量的候选图片,并衡量对用户体验的影响。不同的图片可能会产生不同的结果,并且系统对每张图片应用的优化取决于其在页面中的大小以及用户所用的设备。例如,与电子商务商品详情页上的缩略图相比,全宽主打图片可能需要更多变体。
延迟加载
您可以使用 loading
属性指示浏览器在图片显示在视口中时延迟加载图片。属性值为 lazy
时,表示在图片位于视口内(或附近)之前,浏览器不会下载图片。这可以节省带宽,让浏览器能够优先渲染视口中已有的关键内容所需的资源。
decoding
decoding
属性用于告知浏览器应如何解码图片。值为 async
表示图片可以异步解码,这可能会缩短渲染其他内容的时间。值为 sync
表示图像应与其他内容同时呈现。默认值 auto
允许浏览器决定最适合用户的选项。
图片演示
知识测验
哪些图片格式支持无损压缩?
哪些图片格式支持有损压缩?
宽度描述符(例如 1000w
)如何向浏览器告知 srcset
属性中指定的候选图片?
sizes
属性会向浏览器告知它应用到的 <img>
元素的哪些信息?
<img>
元素的 srcset
中指定的哪个候选项。
<img>
元素的 srcset
属性加载的图片的固有宽度。
下一个:视频表现
虽然图片可能是网络上最常见的媒体类型,但在性能方面,您需要考虑的远不止图片这一项。视频是网络上常用的另一种媒体类型,并且具有自己的性能注意事项。在本课程的下一个单元中,探索有关优化视频和如何高效加载视频的一些技巧。