图片性能

图片通常是 Web 上最重最普遍的资源。因此,优化图片可以显著提高您网站的性能。在大多数情况下,优化图片意味着通过发送更少的字节来减少网络时间,但您也可以通过提供针对用户设备适当大小的图片来优化发送给用户的字节数。

可以使用<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 属性,该属性允许您指定浏览器可能使用的一系列可能的图片源。指定的每个图片源都必须包含图片 URL 以及宽度像素密度描述符。

<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 属性指定了浏览器可以从中选择的图片候选列表,以逗号分隔。列表中的每个候选都包含图片的 URL,后跟一个表示图片固有宽度的语法。图片的固有大小是其尺寸。例如,1000w 的描述符表示图片的固有宽度为 1000 像素宽。

使用此信息,浏览器评估 sizes 属性中的媒体条件,并且—在本例中—被指示如果设备的视口宽度超过 768 像素,则图片以 500 像素的宽度显示。在较小的设备上,图片以 100vw—或整个视口宽度显示。

然后,浏览器可以将此信息与 srcset 图片源列表结合起来,以找到最佳图片。例如,如果用户在屏幕宽度为 320 像素且 DPR 为 3 的移动设备上,则图片以 320 CSS 像素 x 3 DPR = 960 设备像素显示。在本例中,最接近大小的图片将是 image-1000.jpg,其固有宽度为 1000 像素 (1000w)。

文件格式

浏览器支持多种不同的图片文件格式。诸如 WebPAVIF 之类的现代图片格式可能比 PNG 或 JPEG 提供更好的压缩,从而使您的图片文件大小更小,因此下载所需的时间更少。通过以现代格式提供图片,您可以减少资源的加载时间,这可能会降低最大内容绘制 (LCP)

WebP 是一种广泛支持的格式,可在所有现代浏览器上运行。WebP 通常比 JPEG、PNG 或 GIF 具有更好的压缩率,同时提供有损无损压缩。即使在使用有损压缩时,WebP 也支持 Alpha 通道透明度—这是 JPEG 编解码器不提供的功能。

AVIF 是一种较新的图片格式,虽然它不像 WebP 那样得到广泛支持,但它确实在浏览器中享有相当不错的支持。AVIF 支持有损和无损压缩,并且测试表明,在某些情况下,与 JPEG 相比,节省超过 50%。AVIF 还提供广色域 (WCG)高动态范围 (HDR) 功能。

压缩

就图片而言,压缩有两种类型

  1. 有损压缩
  2. 无损压缩

有损压缩通过量化来降低图片精度,并且可以使用色度二次采样来丢弃额外的颜色信息。有损压缩对于具有大量噪点和颜色(通常是照片或内容相似的图像)的高密度图像最有效。这是因为有损压缩产生的伪影在这种详细的图像中不太可能被注意到。但是,有损压缩可能对包含锐利边缘(例如线条图、类似鲜明细节或文本)的图像不太有效。有损压缩可以应用于 JPEG、WebP 和 AVIF 图片。

无损压缩通过压缩图像来减小文件大小,而不会丢失任何数据。无损压缩根据像素与其相邻像素的差异来描述像素。无损压缩用于 GIF、PNG、WebP 和 AVIF 图片格式。

您可以使用 SquooshImageOptim 或图片优化服务来压缩图片。压缩时,没有适用于所有情况的通用设置。推荐的方法是尝试不同的压缩级别,直到找到图片质量和文件大小之间的良好折衷方案。一些高级图片优化服务可以为您自动执行此操作,但对于所有用户而言,在经济上可能不可行。

<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> 元素。altwidthheight 属性在 <img> 上定义,并且无论选择哪个 <source> 都使用。

<source> 元素还支持 mediasrcsetsizes 属性。与之前的 <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 像素的宽度显示。在较小的设备上,这将占据整个视口宽度。通过组合 mediasrcset 属性,您可以更好地控制要使用哪个图片。

下表说明了这一点,其中评估了几个视口宽度和设备像素比

视口宽度(像素) 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.jpgimage-1500-sm.jpg 显示在小视口上。此额外信息使您可以进一步压缩图片,因为压缩伪影在该大小和密度下不明显,同时也不会损害桌面设备上的图片质量。

或者,通过调整 srcsetmedia 属性,您可以避免在小视口上提供大图片

<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 根据 Accept 标头在 Apache 服务器上重写图片请求

这与您在图片内容分发网络 (CDN)上找到的行为没有什么不同。图片 CDN 是优化图片并根据用户的设备和浏览器发送最佳格式的出色解决方案。

关键是找到平衡,生成合理数量的图片候选,并衡量对用户体验的影响。不同的图片可能会产生不同的结果,并且应用于每个图片的优化取决于其在页面中的大小以及用户使用的设备。例如,全宽的 Hero 图片可能比电子商务产品列表页面上的缩略图需要更多的变体。

延迟加载

可以告诉浏览器在图片出现在视口中时延迟加载图片,方法是使用 loading 属性。lazy 的属性值告诉浏览器在图片进入(或接近)视口之前不要下载图片。这节省了带宽,使浏览器可以优先处理渲染已在视口中的关键内容所需的资源。

decoding

decoding 属性告诉浏览器应如何解码图片。async 值告诉浏览器可以异步解码图片,从而可能缩短渲染其他内容的时间。sync 值告诉浏览器应与其他内容同时呈现图片。auto 的默认值允许浏览器决定对用户最有利的方式。

图片演示

测试您的知识

哪些图片格式支持无损压缩?

GIF。
正确!
JPEG。
请重试。
PNG。
正确!
WebP。
正确!
AVIF。
正确!

哪些图片格式支持有损压缩?

GIF。
请重试。尽管 GIF 格式仅支持 256 种颜色的有限调色板,但有损编码必须在转换为 GIF 之前完成。
JPEG。
正确!
PNG。
请重试。
WebP。
正确!
AVIF。
正确!

宽度描述符(例如,1000w)告诉浏览器有关 srcset 属性中指定的图片候选的什么信息?

图片的外在宽度—即,在样式应用于页面后,图片在布局中的尺寸
请重试。
图片的固有宽度—即,图片本身的尺寸。
正确!

sizes 属性告诉浏览器有关应用于它的 <img> 元素的什么信息?

逻辑,用于表达给定用户当前视口的尺寸,应加载 <img> 元素的 srcset 中指定的哪个候选。
正确!
要从 <img> 元素的 srcset 属性加载的图片的固有宽度。
请重试。

下一步:视频性能

虽然图片可能是 Web 上使用的最普遍的媒体类型,但它们远非您在性能方面需要牢记的唯一类型。视频是 Web 上使用的另一种常见媒体类型,并且有其自身的性能考虑因素。在本课程的下一个模块中,探索有关优化视频以及如何有效加载视频的一些技术。