前端性能优化--图片篇

前端性能优化--图片

图片格式的选择
JPEG

有损压缩,高品质的压缩方式。图片体积压缩至原有体积的50%以下时,jpg仍然可以保持60%的品质。原理为以24位存储单个图,可以呈现多达1600万种颜色,足以满足大多数场景下对色彩的要求,这一点决定了它压缩前后的质量损耗并不容易被肉眼察觉。

优点:

  • 网站呈现丰富的色彩。

  • 有损压缩,通过压缩大大的减少图片的体积。一般图片用60%级别比较合适,大于75%的压缩等级,图片有明显的质量下降。

  • 无兼容性问题。

缺点:

  • JPEG图像不支持透明度的处理,透明图片使用PNG。

  • 处理矢量图形和logo等线条感较强、颜色对比强烈的图像时,人为压缩的图片模糊会相当明显。

使用场景:

  • 适用于色彩丰富的图片,日常开发中,JPEG图片经常作为大的背景图、轮播图或banner图出现。
PNG

无损压缩,高保真的图片格式。同时支持8位和24位二进制的位数,八位的png最多指出256种颜色,24位可以呈现约1600万种。

优点:

  • 网站呈现丰富的色彩,更强的色彩表现力,对线条的处理更加细腻。

  • 支持透明度处理,透明图片的使用。

缺点:

  • 体积太大

使用场景:

  • 线条和对比度处理更具优势,我们主要用它来呈现小的logo、颜色简单且对比强烈的图片或对比等。

  • 添加透明度,使用透明图片。

GIF

最多支持256种颜色的8位无损图片格式。

优点:

  • 支持256种颜色,文件体积小。

  • 支持透明。

  • 支持动画。

缺点:

  • 只支持简单色彩的图片。

使用场景:

  • 展示无限循环的动画,比如图标、表情、广告位等。

  • 简单色彩的图片使用。

webP

同时提供了有损压缩和无损压缩(可逆压缩)的图片文件格式。像JPEG一样对细接丰富的图片信手拈来,像PNG一样支持透明,像GIF一样可以显示动态图片。

优点:

  • 色彩丰富。

  • 支持透明。

  • 支持动态图片。

  • 无损压缩比PNG压缩减少了45%的文件大小。

缺点:

  • 浏览器对webP支持并不普遍。ios系统基本不支持。
图片压缩
有损压缩

在压缩文件大小的过程中,损失了一部分图片的信息,也降低了图片的质量,并且这种损失是不可逆的。常见的压缩手段是按照一定的算法将邻近的像素点进行合并,去除了人肉眼无法识别的图片细节。jpg图片使用的就是有损压缩。

无损压缩

在压缩的过程中,图片的质量没有任何损伤。任何时候都可以从无损压缩过的图片中恢复出原来的信息。压缩算法是对图片的所有的数据进行编码压缩,能在保证图片的质量的同时降低图片的体积。例如png、gif使用的就是无损压缩。

类型 动画 压缩类型 浏览器支持 透明度
GIF 支持 无损 所有 支持
PNG 不支持 无损 所以 支持
JPEG 不支持 有损 所以 不支持
webP 支持 无损或有损 部分支持 支持
压缩工具

https://tinypng.com/

https://zhitu.isux.us/

https://compressor.io/

webpack 压缩

webpack配置imge-webpack-loader进行图片压缩

1.安装依赖

npm install --save-dev image-webpack-loader

2.配置webpack

module.exports = {
...
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: [
          {
            loader: 'file-loader',
            options: {
              name: '[name].[hash:7].[ext]'
            },
          },
          {
            loader: 'image-webpack-loader',
            options: {
              mozjpeg: {
                progressive: true,
                quality: 50,
              },
              optipng: {
                enabled: true,
              },
              pngquant: {
                quality: [0.5, 0.65],
                speed: 4,
              },
              gifsicle: {
                interlaced: false,
              }
            },
          },
        ],
      },
    ],
  },
}
使用雪碧图

雪碧图,CSS Sprites,国内也叫 CSS 精灵,是一种 CSS 图像合成技术,主要用于小图片显示。

浏览器请求资源的时候,同源域名请求资源的时候有最大并发限制,chrome 为 6 个,就比如你的页面上有 10 个相同 CDN 域名小图片,那么需要发起 10 次请求去拉取,分两次并发。第一次并发请求回来后,发起第二次并发。如果你把 10 个小图片合并为一张大图片的画,那么只用一次请求即可拉取下来 10 个小图片的资源。减少服务器压力,减少并发,减少请求次数。

优点:

  • 减少请求个数。

缺点:

  • 生成图片体积大,减少请求个数同时增加了图片大小。
webpack合成雪碧图

有相应的插件提供了自动合成雪碧图的功能并且可以自动生成对应的样式文件webpack-spritesmith

var path = require('path')
var SpritesmithPlugin = require('webpack-spritesmith')

module.exports = {
  // ...
  plugins: [
    new SpritesmithPlugin({
      src: {
        cwd: path.resolve(__dirname, 'src/ico'),
        glob: '*.png',
      },
      target: {
        image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
        css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.styl'),
      },
      apiOptions: {
        cssImageRef: '~sprite.png',
      },
    }),
  ],
}

将src/ico目录下的所有png文件合成雪碧图,并且输出到对应目录,同时还可以生成对应的样式文件,样式文件的语法会根据你配置的样式文件的后缀动态生成。

使用base64格式

将图片转换为base64编码字符串inline到页面或css中。

优点:

  • 性能提升:减少http请求,base64可以随着HTML下载到本地。

  • 加密:用户无法一眼看到图片的内容,只看到编码。

  • 方便引用:全局公共文件内加类名。

缺点:

  • 图片大,图片色彩层次比较丰富,不适合这种方式,base64编码后文件过大,增加HTML页面的大小,影响加载速度。
webpack配置url-loader
module.exports = {
...
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10240,
          name: utils.assetsPath('img/[name].[hash:7].[ext]'),
        }
      },
    ],
  },
}
图片懒加载

图片懒加载的原理就是暂时不设置图片的 src 属性,而是将图片的 url 隐藏起来,比如先写在 data-src 里面,等当前图片是否到了可视区域再将图片真实的 url 放进 src 属性里面,从而实现图片的延迟加载。

优点:

  • 减少资源的加载,页面启动只加载首屏的图片,这样能明显减少服务器的压力和流量,也能减小浏览器的负担。

  • 防止并发加载的资源过多而阻塞js的加载,影响整个网站的启动,影响用户体验。

  • 节省用户流量,有些用户并不想全部看完,全部加载会耗费大量流量。

js代码
function lazyload() {
  let viewHeight = document.body.clientHeight //获取可视区高度
  let imgs = document.querySelectorAll('img[data-src]')
  imgs.forEach((item, index) => {
    if (item.dataset.src === '') return

    // 用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置
    let rect = item.getBoundingClientRect()
    if (rect.bottom >= 0 && rect.top < viewHeight) {
      item.src = item.dataset.src
      item.removeAttribute('data-src')
    }
  })
}

// 可以使用节流优化一下
window.addEventListener('scroll', lazyload)
IntersectionObserver计算位置
const imgs = document.querySelectorAll('img[data-src]')
const config = {
  rootMargin: '0px',
  threshold: 0,
}
let observer = new IntersectionObserver((entries, self) => {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      let img = entry.target
      let src = img.dataset.src
      if (src) {
        img.src = src
        img.removeAttribute('data-src')
      }
      // 解除观察
      self.unobserve(entry.target)
    }
  })
}, config)

imgs.forEach((image) => {
  observer.observe(image)
})
图片预加载

将图片提前加载到本地缓存中,从而提升用户体验。

1.css和JavaScript实现预加载
#preload-01 {
  background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px;
}
#preload-02 {
  background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px;
}
#preload-03 {
  background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px;
}
function preloader() {
  if (document.getElementById) {
    document.getElementById('preload-01').style.background =
      'url(http://domain.tld/image-01.png) no-repeat -9999px -9999px'
    document.getElementById('preload-02').style.background =
      'url(http://domain.tld/image-02.png) no-repeat -9999px -9999px'
    document.getElementById('preload-03').style.background =
      'url(http://domain.tld/image-03.png) no-repeat -9999px -9999px'
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload
  if (typeof window.onload != 'function') {
    window.onload = func
  } else {
    window.onload = function () {
      if (oldonload) {
        oldonload()
      }
      func()
    }
  }
}
addLoadEvent(preloader)
2.使用JavaScript实现预加载
function preloader() {
  if (document.images) {
    var img1 = new Image()
    var img2 = new Image()
    var img3 = new Image()
    img1.src = 'http://domain.tld/path/to/image-001.gif'
    img2.src = 'http://domain.tld/path/to/image-002.gif'
    img3.src = 'http://domain.tld/path/to/image-003.gif'
  }
}
function addLoadEvent(func) {
  var oldonload = window.onload
  if (typeof window.onload != 'function') {
    window.onload = func
  } else {
    window.onload = function () {
      if (oldonload) {
        oldonload()
      }
      func()
    }
  }
}
addLoadEvent(preloader)
渐进式图片

高品质图像加载完之前会先显示低画质版本。低画质版本由于画质低、压缩率高、尺寸小、加载很快。

  • 普通图片渲染时,数据将按照存储时的顺序从上到下逐行扫描被显示出来的,直到所有的数据都被读取完毕,就完成了整张图片的显示。

  • 渐进式图片渲染过程中,会先显示整个图片的模糊轮廓,随着扫描次数的增加,图片变得越来越清晰。这种格式的主要优点是在网络较慢的情况下,可以看到图片的轮廓知道正在加载的图片大概是什么。

注:

很多工具和库都支持导出渐进式JPEG,比如 ImageMagick, libjpeg, jpegtran, jpeg-recompress以及imagemin。 也可以使用 gulp-imagemin 进行批量转换。

Photoshop导出渐进式图片,保存为JPEG格式,勾选连续。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容