图片通常是网络上最占用空间且最普遍的资源。因此,优化图片可以显著提升网站的性能。 在大多数情况下,优化图片意味着通过发送更少的字节来缩短网络时间,但您也可以通过提供适合用户设备的图片来优化发送给用户的字节数。
您可以使用 <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 相比,AVIF 可节省超过 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 代码段中,宽度描述符已被移除,取而代之的是设备像素比描述符。即使在 DPR 为 3 的设备上,移动设备上投放的图片也仅限于 /image-500.jpg
或 /image-1000.jpg
。
如何管理复杂性
处理自适应图片时,您可能会发现每张图片都有许多不同的尺寸变体和格式。在上面的示例中,使用了每种尺寸的变体,但排除了 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 图像。
您几乎可以在任何类型的 Web 服务器中根据 Accept
请求标头的内容修改响应,例如,您可以使用 mod_rewrite
在 Apache 服务器上根据 Accept
标头重写图片请求。
这与您在图片内容分发网络 (CDN) 上看到的行为类似。图片 CDN 是一种出色的解决方案,可用于优化图片并根据用户的设备和浏览器发送最佳格式。
关键在于找到平衡点,生成合理数量的候选图片,并衡量对用户体验的影响。不同的图片可能会产生不同的效果,而应用于每张图片的优化取决于该图片在网页中的大小以及用户使用的设备。例如,全宽主打图片可能需要比电子商务商品详情页面上的缩略图更多的变体。
延迟加载
可以使用 loading
属性告知浏览器在图片出现在视口中时延迟加载图片。属性值为 lazy
时,浏览器不会下载图片,直到图片位于(或接近)视口中。这样可以节省带宽,让浏览器优先处理渲染视口中已有的关键内容所需的资源。
decoding
decoding
属性用于告知浏览器应如何解码图片。值为 async
时,浏览器可以异步解码图片,从而可能缩短渲染其他内容的时间。值为 sync
时,浏览器会同时呈现图片和其他内容。auto
的默认值允许浏览器决定最适合用户的值。
图片演示
知识测验
哪些图片格式支持无损压缩?
哪些图片格式支持有损压缩?
宽度描述符(例如 1000w
)会向浏览器告知 srcset
属性中指定的候选图片的相关信息,具体是什么?
sizes
属性会向浏览器告知有关其所应用到的 <img>
元素的哪些信息?
<img>
元素的 srcset
属性加载的图片的固有宽度。
<img>
元素的 srcset
中指定的哪个候选对象的逻辑,具体取决于用户当前视口的尺寸。
接下来:视频表现
虽然图片可能是网络上使用的最普遍的媒体类型,但在性能方面,您需要考虑的远不止图片。视频是另一种在整个网络中使用的常见媒体类型,并且有其自身的性能注意事项。在本课程的下一个模块中,您将探索一些有关优化视频以及如何高效加载视频的技术。