这是 web 性能优化的第二篇, 上一篇在下面看点击查看:
Web 性能优化: 使用 Webpack 分离数据的正确方法 https://segmentfault.com/a/1190000018368885
图像是 Web 上提供的最基本的内容类型之一. 他们说一张图片胜过千言万语. 但是如果你不小心的话, 图片大小有时高达几十兆.
因此, 虽然网络图像需要清晰明快, 但它们尺寸可以缩小压缩的, 使用加载时间保持在可接受的水平.
在我的网站上, 我注意到我的主页的页面大小 超过了 1.1MB, 图片占了约 88%, 我还注意到我提供的图像比它们需要的大 (在分辨率方面), 显然, 还有很多改进的空间.
我开始阅读 Addy Osmani 的优秀 Essential Image Optimization https://images.guide/ 电子书, 并开始在我的网站上按照他们的建议做了一些图片的优化., 然后再对响应式图像进行了一些研究并应用了它.
这使得页面大小减少到 445kb, 约 62% !
什么是图像压缩?
压缩图像就是在图片保持在可接受的清晰度范围内同时减少文件大小, 我使用 https://github.com/imagemin/imagemin 来压缩站点上的图像.
要使用 imagemin, 确保你已经安装了 Node.JS, 然后打开一个终端窗口, cd 进入项目, 并运行以下命令:
NPM install imagemin
然后创建一个名为 imagemin.JS 的新文件, 写入下面的内容:
- const imagemin = require('imagemin');
- const PNGImages = 'assets/images/*.png';
- const JPEGImages = 'assets/images/*.jpg';
- const output = 'build/images';
你可以根据自己的需要更改 PNGImages,JPEGImages 和 output 的值, 以符合你的项目结构.
此外要执行图片压缩, 还需要根据要压缩的图像类型安装对应的插件.
JPEG/JPG
JPG 的优点
JPG 最大的特点是 有损压缩. 这种高效的压缩算法使它成为了一种非常轻巧的图片格式. 另一方面, 即使被称为 "有损" 压缩, JPG 的压缩方式仍然是一种高质量的压缩方式: 当我们把图片体积压缩至原有体积的 50% 以下时, JPG 仍然可以保持住 60% 的品质. 此外, JPG 格式以 24 位存储单个图, 可以呈现多达 1600 万种颜色, 足以应对大多数场景下对色彩的要求, 这一点决定了它压缩前后的质量损耗并不容易被我们人类的肉眼所察觉 -- 前提是你用对了业务场景.
JPG 使用场景
JPG 适用于呈现色彩丰富的图片, 在我们日常开发中, JPG 图片经常作为大的背景图, 轮播图或 Banner 图出现.
JPG 的缺陷
有损压缩在上文所展示的轮播图上确实很难露出马脚, 但当它处理矢量图形和 Logo 等线条感较强, 颜色对比强烈的图像时, 人为压缩导致的图片模糊会相当明显.
此外, JPEG 图像不支持透明度处理, 透明图片需要召唤 PNG 来呈现.
使用 MozJPEG 压缩 jpeg
这里使用 Mozilla 的 MozJPEG https://github.com/mozilla/mozjpeg 工具, 该工具可以通过 https://www.npmjs.com/package/imagemin-mozjpeg 作为 Imagemin 插件使用. 你可以通过运行以下命令来安装它:
NPM install imagemin-mozjpeg
然后将以下内容添加到的 imagemin.JS 中:
- const imageminMozjpeg = require('imagemin-mozjpeg');
- const optimiseJPEGImages = () =>
- imagemin([JPEGImages], output, {
- plugins: [
- imageminMozjpeg({
- quality: 70,
- }),
- ]
- });
- optimiseJPEGImages()
- .catch(error => console.log(error));
可以通过在终端中运行 node imagemin.JS 来运行脚本. 这将处理所有 JPEG 图像, 并将优化后的版本放 build/images 文件夹中.
我发现将 quality 设置为 70 在大多数情况下可以产生足够清晰的图像, 但你的项目需求可能不同, 可以自行设置合适的值.
默认情况下, MozJPEG 生成渐进式 jpeg, 这会导致图像从低分辨率逐渐加载到高分辨率, 直到图片完全加载为止. 由于它们的编码方式, 它们也比原始的 jpeg 略小.
你可以使用 Sindre Sorhus 提供的这个命令行工具 https://www.npmjs.com/package/is-progressive-cli 来检查 JPEG 图像是否是渐进式的.
Addy Osmani 已经很好地总结了使用渐进式 jpeg 的优缺点. 对我来说, 我觉得利大于弊, 所以我坚持使用默认设置.
如果你更喜欢使用原始的 jpeg, 可以在 options 对象中将 progressive 设置为 false. 另外, 请确保 https://www.npmjs.com/package/imagemin-mozjpeg 版本的变化, 请重新查看对应文档.
PNG (PNG-8 与 PNG-24)
PNG 的优缺点
PNG(可移植网络图形格式) 是一种无损压缩的高保真的图片格式. 8 和 24, 这里都是二进制数的位数. 按照我们前置知识里提到的对应关系, 8 位的 PNG 最多支持 256 种颜色, 而 24 位的可以呈现约 1600 万种颜色.
PNG 图片具有比 JPG 更强的色彩表现力, 对线条的处理更加细腻, 对透明度有良好的支持. 它弥补了上文我们提到的 JPG 的局限性, 唯一的缺点就是体积太大.
PNG 应用场景
前面我们提到, 复杂的, 色彩层次丰富的图片, 用 PNG 来处理的话, 成本会比较高, 我们一般会交给 JPG 去存储.
考虑到 PNG 在处理线条和颜色对比度方面的优势, 我们主要用它来呈现小的 Logo, 颜色简单且对比强烈的图片或背景等.
使用 pngquant 优化 PNG 图像
https://pngquant.org/ 是我优化 PNG 图像的首选工具, 你可以通过 https://www.npmjs.com/package/imagemin-pngquant 使用它:
NPM install imagemin-pngquant
然后将以下内容添加到 imagemin.JS 文件中:
- const imageminPngquant = require('imagemin-pngquant');
- const optimisePNGImages = () =>
- imagemin([PNGImages], output, {
- plugins: [
- imageminPngquant({ quality: '65-80' })
- ],
- });
- optimiseJPEGImages()
- .then(() => optimisePNGImages())
- .catch(error => console.log(error));
我发现将 quality 设置为 65-80 可以在文件大小和图像质量之间较好的折衷方案.
有了这些设置, 我可以得到一个屏幕截图, 我的网站从 913kb 到 187kb, 没有任何明显的视觉损失, 惊人的 79% 的降幅!
这是两个文件. 看一看, 自己判断一下:
原图 (913kb)
优化后的图像 (187kb)
WebP
WebP 的优点
WebP 像 JPEG 一样对细节丰富的图片信手拈来, 像 PNG 一样支持透明, 像 GIF 一样可以显示动态图片 -- 它集多种图片文件格式的优点于一身. WebP 的官方介绍对这一点有着更权威的阐述:
与 PNG 相比, WebP 无损图像的尺寸缩小了 26%. 在等效的 SSIM 质量指数下, WebP 有损图像比同类 JPEG 图像小 25-34%. 无损 WebP 支持透明度 (也称为 alpha 通道), 仅需 22% 的额外字节. 对于有损 RGB 压缩可接受的情况, 有损 WebP 也支持透明度, 与 PNG 相比, 通常提供 3 倍的文件大小.
将 WebP 图像提供给支持它们的浏览器
WebP https://developers.google.com/speed/webp/ 是谷歌引入的一种相对较新的格式, 它的目标是通过以无损和有损格式编码图像来提供更小的文件大小, 使其成为 JPEG 和 PNG 的一个很好的替代方案.
WebP 图像的清晰度通常可以与 JPEG 和 PNG 相提并论, 而且文件大小要小得多. 例如, 当我将屏幕截图从上面转换到 WebP 时, 我得到了一个 88kb 的文件, 其质量与 913kb 的原始图像相当, 减少了 90% !
看看这三张图片, 你能说出区别吗?
原图 PNG (913kb)
优化 PNG 图像 (187kb)
WebP 图像 (88kb, 可在 Chrome 或 Opera 浏览器中浏览)
就我个人而言, 我认为视觉效果是可以比较的, 而且节省下来的大小是不容忽视的.
既然我们已经认识到在可能的情况下使用 WebP 格式是有价值的, 那么很重要的一点是 - 它不能完全替代 JPEG 和 PNG, 因为浏览器对 WebP 支持并不普遍.
在撰写本文时, Firefox,Safari 和 Edge 都是不支持 WebP 的浏览器.
然而, 根据 https://caniuse.com/#search=WebP 的数据, 全球超过 70% 的用户使用支持 WebP 的浏览器. 这意味着, 通过使用 WebP 图像, 可以为大约 70% 的客户提供更快的 Web 页面及更好的体验.
安装它, 运行以下命令:
NPM install imagemin-webp
然后将以下内容添加到你的 imagemin.JS 文件中:
- const imageminWebp = require('imagemin-webp');
- const convertPNGToWebp = () =>
- imagemin([PNGImages], output, {
- use: [
- imageminWebp({
- quality: 85,
- }),
- ]
- });
- const convertJPGToWebp = () =>
- imagemin([JPGImages], output, {
- use: [
- imageminWebp({
- quality: 75,
- }),
- ]
- });
- optimiseJPEGImages()
- .then(() => optimisePNGImages())
- .then(() => convertPNGToWebp())
- .then(() => convertJPGToWebp())
- .catch(error => console.log(error));
我发现, 将 quality 设置为 85 会生成质量与 PNG 相当但小得多的 WebP 图像. 对于 jpeg, 我发现将 quality 设置为 75 可以在视觉和文件大小之间取得很好的平衡.
提供 html 格式的 WebP 图像
一旦有了 WebP 图像, 可以使用以下标记将它们提供给可以使用它们的浏览器, 同时向不兼容 WebP 的浏览器使用 PNG 或者 jpeg.
- <picture>
- <source srcset="sample_image.webp" type="image/webp">
- <source srcset="sample_image.jpg" type="image/jpg">
- <img src="sample_image.jpg" alt="">
- </picture>
使用此标记, 理解 image/webp 媒体类型的浏览器将下载 Webp 图片并显示它, 而其他浏览器将下载 JPEG 图片.
任何不支持 <picture> 的浏览器都将跳过所有 source 标签, 并加载底部 img 标签. 因此, 我们通过提供对所有浏览器类的支持, 逐步增强了我们的页面.
请注意, 在所有情况下, img 标记都是实际呈现给页面的内容, 因此它确实是语法的必需部分. 如果省略 img 标记, 则不会渲染任何图像.
标签和其中定义的所有 source 都在那里, 以便浏览器可以选择要使用的图片的路径. 选择源图像后, 其 URL 将传给 img 标记, 这就是显示的内容.
这意味着你无需设置 <picture> 或 source 标记的样式, 因为浏览器不会渲染这些标记. 因此, 你可以像以前一样继续使用 img 标签进行样式设置.
总结
正如你所看到的, 优化 Web 上使用的图像的过程并不复杂, 通过减少页面加载时间, 可以为客户带来更好的用户体验, 希望本文对你有所帮助, 共进步!
来源: https://juejin.im/post/5c9434a16fb9a070e76369e5