本文翻译自Optimizing images for the web - an in-depth guide

这篇文章提供了Web开发中涉及图像的一些优化问题:

  • 计算JPG图像文件大小
  • 在线图像优化
  • 自动化方案
  • 图像载入优化
  • 使用CDN
  • WebP图像格式
  • 为高像素密度的屏幕的优化

上面的目录的前几个部分其实讲的就是图像压缩的问题,不过这里他将的特别的入门级,显得比较啰嗦,我会进行一定的简化。

图像性能常常是网页性能糟糕的一个重要因素,尤其是在初始载入的时候。根据的分辨率和图像质量不同,图像的大小可能占据网站总体积的70%以上。不注重图像性能优化很容易让网站的体验变得非常糟糕。没有经验的开发者则常常忽视这个问题。他们也未能及时接触到相关的优化工具。这篇文章的主旨就在于为Web开发者提供网页中图像性能优化的指南。

1 图像压缩

未被压缩的图像大小和很容易通过像素数量乘以通道数确定:长 * 宽 * 24bits(RGB颜色系统)。原始图像的大小是非常大的,因此图像压缩就非常重要。

有一些在线的网站能够提供图像压缩的功能,如:

不过在开发中大批量的图像处理就不适合用这些网页工具了。在复杂的Web工程中我们一般都会使用一些自动化的构建工具,例如 Gulp, Webpack, Parcel 等。这些自动化工具一般都包含有图像优化的插件,可以完全自动化图像优化处理的过程。这样可以确保所有的图像能够正确地优化。

这里坐着推荐的插件是 imagemin。这一插件非常方便与各种CLI工具或者构建工具集成:

2 图像载入优化

上面已经介绍了通过压缩图像而不减低分辨率以减少前端需要下载文件体积的方法。不过如果一次性载入的图像数量比较多,网页的性能还是会很糟糕。

2.1 Lazy Loading

Lazy Loading 是指在需要的时候才载入素材的理念。在我们的场景中,只有位于当前用户可视区域内的图像才需要进行载入。

最简单的 Lazy Loading 方法是:

1
<img src="image.jpg" loading="lazy" alt="sample image" />

也有一些基于 JavaScript 的解决方案:

2.2 Progressive images

Lazy Loading 的问题在于,从 UX 设计角度来看,用户在等待图像载入的时候,面对的是一个空的画面,这个设计不是特别的友好。Progressive images 的概念就是,我们可以先载入一个低质量的图像放在那里,然后载入高质量的图像。低质量的图像体积要小很多,可以很快的完成。这个图像质量逐渐改善的过程也可以分成多步,如下图:

这种设计给予用户一种速度的错觉。用户可以看着图片变得越来越清晰,而非只是盯着一个空白区域。这里是一个 JavaScript 实现的 Progressive images: progressive-image

2.3 Responsive images

使用正确尺寸的图像也是一个需要注意的点。

例如,我们有一个图像,在桌面端的最大宽度为1920px,在平板端的最大宽度为1024px,移动端的最大宽度为568px。简单的方法是使用一个1920px的图像用于所有的情况。但是这样就意味着平板用户和移动用户需要载入其实完全不必要的数据。

我么可以使用 picture 元素来告诉浏览器根据设备类型去下载哪个图片。这个元素大约被93%的用户的浏览器支持,不过我们可以内嵌使用 img 元素来实现 fallback。

1
2
3
4
5
<picture>
<source media="(min-width: 1025px)" srcset="image_desktop.jpg">
<source media="(min-width: 769px)" srcset="image_tablet.jpg">
<img src="image_mobile.jpg" alt="Sample image">
</picture>

3 使用 CDN

一些 CDN,例如 Cloudinary 还有 Cloudflare 可以在服务器上进行图像优化。如果你使用了 CDN 服务,注意留意一下 CDN 服务提供商是否提供了图像优化的服务。这就可以让我们省下很多功夫了。

4 WebP 图像格式

最近看到了好多 WebP 格式的图像啊,尤其是微信公众号的文章里都是这种格式。别的优点还不清楚,不过给图像直接下载设置了一点障碍。

WebP 图像格式由 Google 开发,是一种特别针对 Web 场景优化的格式。根据 canIUse 的数据,WebP 格式的图像在大约 80% 的场景下使用。为了保险设计 Fallback机制,例如:

1
2
3
4
5
<picture>
<source type="image/webp" srcset="image.webp" />
<source srcset="image.jpg" />
<img src="image.jpg" alt="Sample image" />
</picture>

有很多在线转化工具可以将图像转化成 WebP 格式。如果 CDN 能够提供这种支持就是最为省心了。

5 为高像素密度的屏幕的优化

这更多的是 UX 方面的改善,而非性能方面的改善。例如在我们子啊一个 768px 宽度的屏幕中展示 768px x 320px 的图像,而这个设备的像素密度是2x,则设备屏幕实际的像素宽度是 2 x 768 = 1536px。那么实际上我们是将一个 768px 的图像拉伸了两倍。为了最优化图像在高分辨率设备上的显示,我们需要额外指定一个两倍甚至三倍分辨率的图像。这一图像通过srcset属性来设置:

1
<img src="image-1x.jpg" srcset="image-2x.jpg 2x" alt="Sample image" />

一个完整的响应式的,支持 WebP/PNG 格式以及高分辨率屏幕的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
<picture>
<source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 440px)">
<source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 440px)">
<source srcset="./images/webp/hero-image-550-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 767px)">
<source srcset="./images/minified/hero-image-550-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 767px)">
<source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 1023px)">
<source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 1023px)">
<source srcset="./images/webp/hero-image-760-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 1919px)">
<source srcset="./images/minified/hero-image-760-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 1919px)">
<source srcset="./images/webp/hero-image-960-min.webp" type="image/webp">
<source srcset="./images/minified/hero-image-960-min.png">
<img src="./images/minified/hero-image-960-min.png" alt="Example">
</picture>