1. 背景
在项目中,图片可以说是必备的文件内容,但是面对经常与我打交道的图片,我却对它的使用了解得少之又少。近期,我与同事完成了本公司的官网工程,期间对于图片的操作,我使用了懒加载、雪碧图和压缩等方式进行优化,但是在面对近百张图片时,图片的内存依然占据了140MB,对此,我特意了解一下关于图片优化的知识。
2. 选择正确的图片格式
2.1 考虑是否可以通过技术代替图片
在项目中,我们应该问自己一个问题,是否只有图片才能实现想要的效果,一个好的设计应简单易用,而且始终都能带来最佳性能。减少一个图片资源的使用,通常都会使性能得到一定的提升,但也不是说,所有的效果都不使用图片,如果图片资源的所占内存比其他方式实现效果的所占内容小,那么使用图片会是最佳策略,这个就需要找到一个平衡点。
比如:一个">"箭头图标,我们可以使用css来代替图片。
2.2 选择合适的图片格式
矢量图非常适合内容简单的图片,它在任何分辨率和缩放设置下都可以提供清晰的效果,因此非常合适需要以不同尺寸显示的高分辨率屏幕和素材资源。
位图非常适合内容复杂的图片,这种情况下,使用矢量图就不是一个合适的方案。位图不会自动适配不同分辨率或缩放的情况,像素越高,内容显示越精细,但是所占内存也越大,我们不能一味地使用高倍的图片,需要自适应图片。
位图的格式有很多种,比如PNG、JPEG、WebP、AVIF等,不同的格式之前,压缩算法、动画、透明度通道都不一样,需要综合考虑所需的视觉效果和功能要求,选择“正确的格式”,格式对比如下:
格式 | 透明度 | 动画 | 浏览器 |
PNG | 是 | 否 | ALL |
JPEG | 否 | 否 | ALL |
WebP | 是 | 是 | 所有现代浏览器。请参考我可以使用吗? |
AVIF | 是 | 是 | 否。请参考我可以使用吗? |
WebP和AVIF通常比PNG和JPEG有更好的压缩效果,但是兼容性一般般,建议使用WebP与PNG或JPEG一起使用,如需了解详情,请参考使用WebP图片。
2.3 参考文献
3. 选择正确的压缩级别
图片通常占据了网页上下载字节的大部分,通常也占用大量的视觉空间。因此,优化图片通常可以最大限度地节省网站的流量并提高网站性能:浏览器需要下载的字节数越少,对客户端带宽的竞争就越少,浏览器下载并在屏幕上呈现有用内容的速度就越快。
3.1 矢量图压缩
一个SVG文件通常会包含大量的元数据,比如图层信息、注释和XML命名空间,但是在浏览器中渲染资源通常不需要这些元数据,因此,最好通过使用 SVGO 等工具来缩减 SVG 文件的大小。
3.2 位图压缩
Imagemin 是图片压缩的绝佳选择,因为它支持各种图片格式,并且可以与构建脚本和构建工具轻松集成。Imagemin 可作为 CLI 和 npm 模块提供。通常,npm 模块是最佳选择,因为它提供了更多配置选项。
Imagemin 是围绕“插件”构建的。插件是用于压缩特定图片格式的 npm 软件包(例如,“mozjpeg”可压缩 JPEG)。热门图片格式可能有多个插件可供选择。
选择插件时,最重要的考虑因素是它是“有损”还是“无损”。在无损压缩中,不会丢失任何数据。有损压缩可减小文件大小,但代价是可能会降低图片质量。如果插件未提及它是“有损”还是“无损”的,您可以通过其 API 来判断:如果您可以指定输出的图片质量,则它是“有损”的。
图片格式 | 有损插件 | 无损插件 |
JPEG | imagemin-mozjpeg | imagemin-jpegtran |
PNG | imagemin-pngquant | imagemin-optipng |
GIF | imagemin-giflossy | imagemin-gifsicle |
SVG | imagemin-svgo | |
WebP | imagemin-webp | imagemin-webp |
Imagemin CLI
Imagemin CLI 支持 5 种不同的插件:imagemin-gifsicle、imagemin-jpegtran、imagemin-optipng、imagemin-pngquant 和 imagemin-svgo。Imagemin 会根据输入的图片格式使用适当的插件。
如需压缩“images/”目录中的图片并将其保存到同一目录,请运行以下命令(覆盖原始文件):
$ imagemin images/* --out-dir=images
Imagemin npm 模块(推荐)
如果您使用上述构建工具之一,请使用 webpack、gulp 或 grunt 检出 Imagemin 的 Codelab。
您还可以将 Imagemin 本身用作 Node 脚本。以下代码使用“imagemin-mozjpeg”插件将 JPEG 文件压缩为 50 画质(“0”表示最差;“100”表示最佳):
const imagemin = require('imagemin');
const imageminMozjpeg = require('imagemin-mozjpeg');
(async() => {
const files = await imagemin(
['source_dir/*.jpg', 'another_dir/*.jpg'],
{
destination: 'destination_dir',
plugins: [imageminMozjpeg({quality: 50})]
}
);
console.log(files);
})();
使用Imagemin压缩图片时,请务必尝试使用 WebP 和 AVIF 格式,看看与旧格式相比,能否以较小的体积提供相同的图像。
但是,请注意不要过度压缩光栅图像。一种很好的解决方案是使用图片优化 CDN 找到最适合您的压缩设置,但您也可以使用 Butteraugli 等工具估算视觉差异,以免过度对图片编码并导致图片画质降低。
3.3 参考文献
4. 用视频替换 GIF 动画,加快网页加载速度
需要知道,GIF 动画文件内存一般是视频文件内存的好几倍,所以,我们需要尽可能的使用视频替换 GIF动画。
视频通常分为MPEG和WebM视频,MPEG的兼容性比WebM要好,但是WebM的内存比MPEG内存要小的多,所以,我建议同时使用这两种视频类型。
4.1 创建 MPEG 视频
您可以通过多种方式将 GIF 转换为视频,本指南中使用的是 FFmpeg。如需使用 FFmpeg 将 GIF (my-animation.gif
) 转换为 MP4 视频,请在控制台中运行以下命令:
ffmpeg -i my-animation.gif -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4
这会告知 FFmpeg 将 my-animation.gif
作为由 -i
标志表示的输入,并将其转换为名为 my-animation.mp4
的视频。
libx264 编码器仅适用于尺寸均匀的文件,例如 320x240 像素。如果输入 GIF 的尺寸是奇数,您可以添加剪裁过滤器,以避免 FFmpeg 抛出“高度/宽度不可被 2 整除”错误:
ffmpeg -i my-animation.gif -vf "crop=trunc(iw/2)*2:trunc(ih/2)*2" -b:v 0 -crf 25 -f mp4 -vcodec libx264 -pix_fmt yuv420p my-animation.mp4
4.2 制作 WebM 视频
如需使用 FFmpeg 将 my-animation.gif
转换为 WebM 视频,请在控制台中运行以下命令:
ffmpeg -i my-animation.gif -c vp9 -b:v 0 -crf 41 my-animation.webm
4.3 视频的使用
GIF 动画有三个关键特征,视频需要模仿:
- 它们会自动播放。
- 它们会不断循环(通常情况下,但可以防止循环)。
- 他们保持沉默。
幸运的是,您可以使用 <video>
元素重新创建这些行为。
<video autoplay loop muted playsinline></video>
具有这些属性的 <video>
元素会自动播放、无限循环、不播放任何音频并内嵌播放(即非全屏播放),这是动画 GIF 所期望的所有特征点行为!🎉
最后,<video>
元素需要一个或多个 <source>
子元素,以指向浏览器可供选择的不同视频文件,具体取决于浏览器的格式支持。请同时提供 WebM 和 MP4,这样一来,如果浏览器不支持 WebM,可以回退到 MP4。
<video autoplay loop muted playsinline>
<source src="my-animation.webm" type="video/webm">
<source src="my-animation.mp4" type="video/mp4">
</video>
主要注意的是:浏览器不会推测哪个
<source>
最佳,因此<source>
的顺序很重要。
4.4 参考文献
5. 提供自适应图片
提供自适应图片时,需要评估用户设备的显示功能,并根据这些条件从一组最适合显示的候选图片中选择一个。如前所述,结果不是将过多的图像数据传送给无法受益于这些数据的设备,而是针对设备传送大小适当的图片。对于手机和平板电脑等较小的设备,这相当于与笔记本电脑等屏幕较大的设备相比减少了流量消耗。
5.1 调整图片大小
sharp npm 软件包和 ImageMagick CLI 工具是两种最受欢迎的映像大小调整工具。
Sharp 软件包是自动调整图片大小的理想之选(例如,为网站上的所有视频生成多种尺寸的缩略图)。它可以快速轻松地与构建脚本和工具集成。另一方面,ImageMagick 可以完全从命令行使用,因此可以方便地一次性调整图片大小。
sharp
如需将此代码用作 Node 脚本,请将此代码保存为项目中的单独脚本,然后运行该脚本来转换图片:
const sharp = require('sharp');
const fs = require('fs');
const directory = './images';
fs.readdirSync(directory).forEach(file => {
sharp(`${directory}/${file}`)
.resize(200, 100) // width, height
.toFile(`${directory}/${file}-small.jpg`);
});
ImageMagick
如需将图片大小调整为原始大小的 33%,请在终端中运行以下命令:
convert -resize 33% flower.jpg flower-small.jpg
若要将图片大小调整为不超过 300 像素(宽 x 高)200 像素,请运行以下命令:
# macOS/Linux
convert flower.jpg -resize 300x200 flower-small.jpg
# Windows
magick convert flower.jpg -resize 300x200 flower-small.jpg
5.2 提供多个图片版本
在实际工程中,应该创建多少个映像版本呢?
对于这个问题,没有一个“正确”的答案,通常会投放 3-5 种不同尺寸的图片。传送图片越大,性能越好,但会占用服务器空间,并且需要编写更多 HTML 代码。
指定多个映像版本,浏览器将选择要使用的最佳版本:
<img src="flower-large.jpg" srcset="flower-small.jpg 480w, flower-large.jpg 1080w" size="50vw">
5.3 通过指定尺寸来避免布局偏移
在 HTML 中提供图片时,请务必使用正确的 width
和 height
属性,以便浏览器知道要在布局中为图片分配多少空间,如果没有这些属性或等效的 CSS 大小,浏览器便无法了解图片在加载之前会占用多少空间,这会导致文档中的布局偏移。
除了明确提供宽度和高度之外,您还可以选择使用图片上的 CSS aspect-ratio 属性。这与 width
和 height
属性对元素尺寸的影响类似,因为容器将保持一致的宽高比。不过,不同之处在于这可能会导致所使用的宽高比与图片实际采用的宽高比不同,因此您可能需要使用 object-fit
设置来确保图片在此清晰的 16/9 视图中不失真。
5.4 参考文献
6. 使用 WebP 图片
WebP 图片比对应的 JPEG 和 PNG 图片小,文件大小通常可缩减 25-35%。这会缩减页面大小并提升性能。
WebP 可以很好地替代 JPEG、PNG 和 GIF 图片。此外,WebP 同时提供无损压缩和有损压缩。在无损压缩中,不会丢失任何数据。有损压缩可减少文件大小,但代价可能是降低图片质量。
6.1 将图片转换为 WebP 格式
用户通常使用以下其中一种方法将图片转换为 WebP:cwebp 命令行工具或 Imagemin WebP 插件(npm 软件包)。如果您的项目使用构建脚本或构建工具(例如 Webpack 或 Gulp),则 Imagemin WebP 插件通常是最佳选择,而 CLI 则非常适合简单的项目,或者您只需要转换一次图片。
将图片转换为 WebP 格式时,您可以选择设置各种压缩设置,但对于大多数人而言,唯一需要关注的就是质量设置。您可以指定介于 0(最差)到 100(最佳)之间的质量级别。您可以多加尝试一下,看看哪种级别能满足您的需求,在图片质量和文件大小之间做出适当的权衡。
使用 cwebp
使用 cwebp 的默认压缩设置转换单个文件:
cwebp images/flower.jpg -o images/flower.webp
使用 50
质量级别转换单个文件:
cwebp -q 50 images/flower.jpg -o images/flower.webp
转换目录中的所有文件:
for file in images/*; do cwebp "$file" -o "${file%.*}.webp"; done
使用 Imagemin
此脚本将转换 images
目录中的文件并将其保存到 compressed_images
目录中。
const imagemin = require('imagemin');
const imageminWebp = require('imagemin-webp');
imagemin(['images/*'], {
destination: 'compressed_images',
plugins: [imageminWebp({quality: 50})]
}).then(() => {
console.log('Done!');
});
6.2 WebP 图片的使用
由于 WebP 图片只兼容现在的浏览器,所以,在使用 WebP 图片时,配合PNG或JPEG一起使用,一遍兼容较旧的浏览器,使用方式如下:
<picture>
<source type="image/webp" srcset="flower.webp">
<source type="image/jpeg" srcset="flower.jpg">
<img src="flower.jpg" alt="">
</picture>
浏览器会使用所列出的第一个来源(采用其支持的格式)。如果浏览器不支持 <source>
标记中列出的任何格式,则会回退到加载 <img>
标记指定的图片。
需要注意的是:
- “首选”图片格式(在本例中为 WebP)的
<source>
标记应在其他<source>
标记之前列出。- 应始终添加
<img>
标记,并且该标记应始终列于最后,在所有<source>
标记之后。<img>
标记指定的资源应采用普遍支持的格式(例如 JPEG),以便可以用作后备格式。
6.3 参考文献
7. 使用图片 CDN 优化图片
图片内容分发网络 (CDN) 在优化图片方面表现出色。改用图片 CDN 可将图片文件大小节省 40-80%。
7.1 什么是图片 CDN
图片 CDN 专门从事图片的转换、优化和分发。您也可以将它们看作用于访问和操纵您网站上使用的图片的 API。对于从图片 CDN 加载的图片,图片网址不仅会指示要加载的图片,还会指示大小、格式和质量等参数。这样,您就可以轻松针对不同的用例创建图片变体。
图片 CDN 与构建时图片优化脚本的不同之处在于,它们可根据需要创建新版图片。因此,与构建脚本相比,CDN 通常更适合为每个客户端创建高度自定义的图片。
7.2 图片 CDN 如何使用网址来指示优化选项
图片 CDN 使用的图片网址用于传达与图片以及应应用于图片的转换和优化有关的重要信息。网址格式因图片 CDN 而异,但大体上讲,它们都具有类似功能。下面我们来了解一些最常见的功能。