前端性能优化之图片优化,图片资源减少了57%

8,562 阅读4分钟

本文已参与「掘力星计划」,赢取创作大礼包,挑战创作激励金

图片的优化处理汇总,包括选择合适的图片格式,图片压缩,CSS Sprites(雪碧图,CSS 精灵),图片懒加载,CSS 替换实现,base64 格式,iconfont 字体图标,使用 CDN等等

前言

之前写了一篇前端性能优化实战 从 30s 到 2s的文章,是从大方向上进行优化的,主要是插件的按需引入,加上 gzip 压缩配置。

本篇还是优化同一个系统,不过是从细节优化入手的,主要介绍图片的优化处理

图片优化方案

  1. 图片格式:常用的图片格式有 JPG、PNG、SVG、WebP 等等,选择适合的
  2. 图片压缩:对于清晰度要求不高的图片,可以进行压缩处理
    • 手动压缩推荐 tinypng
    • webpack 插件 image-webpack-loader 压缩
  3. CSS Sprites(雪碧图,CSS 精灵):将多个小图标合成一张图,减少 HTTP 请求次数。通过定位(backround-position)来显示对应的图片,这个对于细节要求比较高
    • 让 UI 帮我们合成,当然自己能合成的话更好
    • webpack-spritesmith 插件
  4. 图片懒加载
    • 对于那种图片比较多的页面,仅展示可视窗口内的图片,其他的等滚动到可视窗口再加载;
    • 图片轮播组件也可以使用懒加载
    • 懒加载方案:图片地址存放 img 标签的某个属性上,例如data-src,当图片再可视窗口范围内时,将 src 属性替换成图片地址data-src的值。
    • Intersection Observer API - Web API 接口 | MDN
    • vue-lazyload
  5. CSS 替换实现
    • 尽量用 CSS 实现图片,不能再考虑切图
    • 使用 CSS3 属性时,尽量考虑到 GPU 硬件加速
  6. 响应式图片加载:不同分辨率的设备使用不同尺寸的图片,适合手机端
  7. base64 格式
    • 将图片 src 换成 base64 格式加载,减少网络请求
    • 图片经过 base64 编码后会变大,增大 HTML 页面的大小,影响加载速度
    • 所以要合理使用此方式,常用在 webpack 的 url-loader 中使用
  8. iconfont 字体图标:减少 HTTP 请求次数
  9. 使用 CDN:有些大图片可以直接放在服务器上,降低访问延时

实战

优化前

图片资源为4.6MB,图片个数为110个:

ic_compare_1_1.png

imagemin-webpack-plugin 图片压缩

根据“优化前分析” => “构建后文件分析”,有四张图片太大,需要优化处理

因为系统需要支持大屏幕显示,一般用的图片都是三倍图,所以图片都会比较大,需要合理处理一下。

(1)配置代码

easywebpack 内置了一些插件,只需要进行简单的配置就可以开启关闭,当然也可以覆盖默认配置,进行自定义配置

// 安装
$ npm install imagemin-webpack-plugin --save-dev

// 配置webpack.config.js
module.exports = {
  plugins: [
    { // 1. 禁用内置图片压缩插件配置(imagemin-webpack-plugin),默认启用
      // imagemini: false, 
      
      // 2. 当然也可以自定义配置
      imagemini: {
        enable: true,
        env: ["prod"],
        type: "client",
        name: "imagemin-webpack-plugin",
        entry: "default",
        args: {
          test: /\.(jpe?g|png|gif|svg)$/i,
          optipng: {
            optimizationLevel: 9,
          },
          pngquant: {
            // 压缩质量
            quality: "20-30",
          },
        },
      },
    },
  ],
};

(2)配置对比

图片资源从 4.6MB 变为 1.7MB,当然我配置的20-30肯定是有些极端的,正常情况下配置70-90

我配置的这么低了,还有一张图片还是很大,可以考虑对其进行单独处理,先手动压缩一下,在进行其他处理

ic_compare_10.png

url-loader base64 转化

小图片考虑使用 url-loader 直接转成 base64 格式,减少网络请求

(1)配置代码:

easywebpack 集成了 url-loader 插件,默认使用如下:

// 配置webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        // 1. 默认禁用
        // urlimage: false 
        
        // 2. 自定义处理
        urlimage: {
          options: { limit: 1024 * 5 }, // 小于5KB转为base64,大于的不转
        },
      },
    ],
  },
};

(2)配置对比

配置后,图片资源从 4.6MB 变为 4.4MB,图片小于 5KB 的都转为 base64 了,图片个数变为50个,减少了60个

ic_compare_10_4.png

同时开启

有一些图片压缩前很大,imagemin 之后很小,这些文件如果用 imagemin-webpack-plugin处理之后,就不会再转为 base64 格式了,因为 loaderplugin 之前执行,url-loader limit 比较的是压缩前的大小。

如果同时开启图片压缩和 base64 转化,结果是仅压缩了,没有转为 base64

解决方案:使用 image-webpack-loader 替代 imagemin-webpack-plugin

(1)配置代码:

需要用如下的配置覆盖默认的配置:

// 安装插件
$ npm install image-webpack-loader --save-dev

// 配置webpack.config.js
module.exports = {
  plugins: [
    {
      imagemini: false, // 禁用
    },
  ],
  module: {
    rules: [
      {
        // urlimage: false // 默认禁用
        urlimage: {
          use: [
            {
              loader: "url-loader",
              options: {
                limit: 1024 * 5, // 小于5KB转为base64
                fallback: "file-loader",
                name: `img/[name].[hash:8].[ext]`,
              },
            },
            {
              loader: "image-webpack-loader",
            },
          ],
        },
      },
    ],
  },
};

(2)配置对比:

图片资源从 4.6MB 变为 2MB,图片资源减少了57%,图片个数由 110 个减为 42 个了,减少了68个

**这个是最合适的,最终也是采用了这个配置**

ic_compare_10_3.png

下一篇: 再战前端性能优化之代码分割,bundle包减少了26%

相关参考文档

  1. 官网 easywebpack plugin 配置

  2. 官网 easywebpack plugin.js 源码

  3. 官网 easywebpack loaders 配置

  4. Github地址 imagemin-webpack-plugin

  5. 解决方案:使用 image-webpack-loader 替代 imagemin-webpack-plugin

  6. url-loader 配置文档