0%

前端性能优化—图像优化

网站作为一种信息传递的媒介,在如今各类的 Web 项目中,图像资源的使用占比越来越大,因此我们应当注意图像资源的使用方式。如果网站中的图像资源未进行恰当的优化,当网站访问量较大时会产生很大的带宽挑战,同时也会造成大尺寸图像请求时间过长等问题。

图像优化问题主要分为两个方面:图像的选取和使用和图像的加载和显示。本篇文章主要讨论图像的选取和使用。

图像基础

图像文件可分为两类:矢量图和位图,每种类型都有自己的优缺点和适用场景。

矢量图

矢量图中的图形元素被定义为一个对象,包括颜色、大小、形状及屏幕位置等信息。

矢量图适合于如文本、logo、控件图标及二维码等形状简单的几何图形

矢量图的优点是能够在任何缩放比例之下呈现同样清晰的展示效果。

矢量图的缺点是对细节的展示效果不够丰富。对于足够复杂的图像,如果要达到照片的效果,通过 SVG 绘制会使得文件大的离谱,即便如此也很难达到照片的真实效果。

位图

位图是通过对矩阵中的栅格进行编码来表示的图像,图像的栅格像素点越多,且每个像素点所能表达的颜色范围越广,则位图图像整体的显示效果就会越逼真。

位图的优点是能提供较为真实复杂的细节体验,但位图会受屏幕分辨率的影响。

常见的位图有:JPEG、GIF、PNG、WebP

有损压缩和无损压缩

图像资源优化的根本思想是压缩,压缩是降低源文件大小的有效方式。图像压缩可分为有损压缩和无损压缩。

具体在选择压缩方式时,我们需要结合具体的业务需求考虑。如果业务上对图像的质量要求较高,则考虑使用无损压缩。

图像格式

JPEG

JPEG使用的是一种有损压缩算法。

用途:用作背景图、轮播图或者一些商品的 banner 图。但是由于有损压缩,当处理 Logo 或者图标时,需要较强的线条感或者强烈的颜色对比的时候,使用 JPEG 可能会出现边界模糊的不加体验,另外JPEG不支持透明度

JPEG包含多种压缩模式,其中常见的有基于基线的和渐进式的。

  • 基线模式:图像加载顺序是自上而下的,当网络较差时,图象是自上而下加载显示的
  • 渐进式:将图像文件分为多次扫描,首先展示一个低质量模糊的图像,最后扫描到的图像信息不断增多,每次扫描过后所展示的图像清晰度也会不断提升

优缺点:渐进式解码速度要比基线慢,另外渐进式压缩得到的图像文件也不一定是最小的。

在实际生活中,我们不难发现,目前渐进式的 JPEG 已经慢慢取代了基线 JPEG 了。在应用时,我们可以使用一些第三方工具来创建渐进式的图像,例如 imagemin、libjpeg、imageMagick。以下是使用 gulp 创建渐进式 JPEG 的代码:

1
2
3
4
5
6
7
8
9
const gulp = require("gulp")
const imagemin = require("gulp-imagemin")
gulp.task("images", () => {
gulp.src("images/*.jpg")
.pipe(imagemin({
progressive: true
}))
.pipe(gulp.dest("dist"))
})

在执行后见流程之后,gulp 会调用 imagemin 的方法把 images 文件夹下所有的 jpg 图像全部进行渐进式编码处理。

GIF

gif 主要是动画图片,但是相比于视频文件,gif 在解码阶段十分耗时,所以出于对性能的考虑,我们应该尽量谨慎选用 gif。

PNG

PNG 是一种无损压缩的高保真图片格式,相比于 JPEG,PNG支持透明度,对线条处理更加细腻,并增强了色彩的表现,不过缺点就是文件体积太大。

优化 PNG:

对于 PNG 图像,我们可以使用 imagemin-pngcrush 来进行优化:

1
2
3
4
5
const imagemin = require("imagemin")
const imageminPngcrudh = require("imagemin-pngcrush")
imagemin(["images/*.png"], "build/images", {
plugins: [imageminPngcrush()]
}).then(()=>console.log("图像优化完成"))

WebP

前面的三种图像文件格式,在呈现位图方面各有优劣:GIF 能呈现动画;JPEG 虽然不支持透明度,但是图像文件的压缩比高;PNG 虽然文件尺寸较大,但支持透明且色彩表现力强。

开发者在使用位图时对于这样的现状就需要先考虑选型。假如有一个统一的图像文件格式,具有之前格式的所有优点就好了。WebP 由此产生。

根据 WebP 官方网站给出的实验数据,当使用 WebP 有损文件时,文件尺寸会比 JPEG 小 25%-34%,而使用 WebP 无损文件时,文件尺寸会比 PNG 小 26%。

但是 WebP 存在一定的兼容性问题

从图中可以看出,除了 IE 浏览器不支持外,其他大部分浏览器都已经支持 WebP。

如何使用 WebP?

我们可以借助工具将原有的 jpg 或者 png 转换为 WebP 格式:

1
2
3
4
5
6
7
loader: [{
test: /\.(jpe?g|png)$/I,
loaders:[
"file-loader",
"webp-loader?{quality: 13}"
]
}]

这里值得注意的是,尽量不要使用低质量的 JPEG 格式进行转换,建议使用高质量的 JPEG 图像进行转换。

兼容性处理?

目前 WebP 不适用于所有浏览器,因此在使用时需要做兼容性处理。

通常处理的思路有两种:

  • 一种是在前端通过 userAgent 判断浏览器版本,然后根据版本选择加载不同的图像。

  • 另一种是可以通过 <picture> 标签来选择显示图像的格式,在 <picture> 标签中添加多个 <source> 标签元素,以及一个包含旧图像格式的 <img> 标签,当浏览器在解析 DOM 的时候,便会对 <picture> 标签中的多个图像源依次进行检测。如果都不支持,就会使用 <img> 标记兼容显示出旧的图像格式。

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

    tips: <picture> 标签的 <source> 标签里面还可以有 media 属性,可以根据不同的 media 来显示不同大小的图像,因此 <picture> 的常见使用场景:

    • 艺术指导(Art direction) —— 针对不同 media 条件裁剪或修改图像
    • 遇到所有浏览器都不支持的特定格式时,提供不同的图像格式

SVG

前面介绍的几种图像都是位图,而 SVG 是矢量图。SVG是基于 XML 语法描述图像形状的文件格式,适合用来表示 Logo 等图标图像。

Base64

Base64 是一种编码方式,它通过将图像的编码直接写入 HTML 或者 CSS 中实现图像的展示。

使用该方式编码展示的图像,无需发送 HTTP 请求,浏览器会自动解析并展示该编码图像。由于 Base64 编码原理的特点,一般经过 Base64 编码后的图像大小会膨胀四分之三。因此,只有对于小图而言,Base64 才能发挥它真正的作用。因此在考虑使用 Base64 编码时,要考虑以下几个条件:

  • 图像文件的实际尺寸是否很小
  • 图像是否真的无法以雪碧图的形式进行引入
  • 图像文件的更新频率是否很低,以避免在使用 Base64 时,增加不必要的维护成本

格式选择建议

  • 尽量使用矢量图,凡是用到图标的场景,应尽可能使用矢量图
  • 对于位图使用的场景,首选 webp 格式
  • 考虑到新技术的兼容性问题,使用 picture 标签进行适配,包含动画时,使用 GIF;需要展示细节并且需要透明度时,使用 PNG;追求更高图像压缩比时,使用 JPEG。此外对于不同缩放比的响应式场景,可以使用不同尺寸的图像,让浏览器根据实际情况进行调用。

总结

  • 适合用矢量图的地方首选矢量图
  • 使用位图时首选webp,对不支持的浏览器场景进行兼容处理
  • 尽量为位图图像格式找到最佳质量设置
  • 删除图像文件中多余的元数据
  • 对图像文件进行必要的压缩
  • 为图像提供多种缩放尺寸的响应式资源
  • 对工程化通用图像处理流程尽量自动化