目录


图片在各大网站随处可见,因为图片的表述比文字更加直观,所以图片成为网站最重要的要素之一。

图片相对其他文件又很大,页面的加载速度很大程度上取决于图片的加载速度,所以我们要对图片进行优化,以此加快页面加载速度,提升用户体验。

1. 图片类型

在平时开发中,我们可能用到的图片类型有以下几种:

  • PNG
  • JPG/JPEG
  • GIF
  • SVG
  • WebP
  • Base64
  • BPG
  • APNG

下面就分别介绍一下这几种图片类型及其使用场景。

1.1 PNG

PNG的全称是便携式网络图形,这是一种无损压缩的位图图形格式,支持索引、灰度、RGB 三种颜色方案以及 Alpha 通道等特性。它是现在网页中使用最广泛的图片格式之一。

PNG是一种无损压缩的图片格式,因为PNG图片的色彩表现力要比其他格式的图片更好,PNG又可以细分为PNG-8、PNG-24、PNG-32。

  • PNG-8只能使用256种颜色,可以设置透明色,支持索引色透明和Alpha透明。
  • PNG-24最多可使用1600万种颜色,色彩度和清晰度相比PNG-8更好,但是不支持透明度。
  • PNG-32则是综合了PNG-8和PNG-24的有点,既有丰富的色彩和清晰度表现,而且还支持设置透明度。

应用场景:

  • 网站的Logo
  • 图片简单,但是对图片质量要求高
  • 雪碧图(又称为精灵图、CSS Sprites)

1.2 JPG/JEPG

JPG/JEPG是另外一种使用的比较多的图片,它是一种有损压缩的格式。在不影响人眼可分别图片质量的前提下,尽可能的压缩图片的大小。所以在色彩表现力上不如PNG。

JPG/JPEG使用的是24位二进制数来表示一个像素,所以可以表示1600万种颜色。

使用场景:

  • 首页轮播图
  • 其他的一些对有图片质量要求不是很高的列表图片

1.3 GIF

GIF是一种基于LWZ算法的连续色调的无损压缩格式。它的压缩率一般在50%左右。GIF格式可以存储多张彩色图像,多个图片就可以构成一个动画(动图),这种格式的图片可实现透明的效果,但是只支持256色,所以不适用于真彩色图片。

使用场景:

  • 较短的动画展示
  • 网站的Loading加载效果

1.4 SVG

SVG是一种基于XML语法的图像格式,全称是可缩放矢量图。严格来说应该是一种开放标准的矢量图形语言,可以进行设计的高分辨率的web图形页面。

SVG本身是可编程性的语言(支持直接插入DOM当中),可被非常多的工具读取和修改。SVG 具有尺寸更小,且可压缩性更强的优势,而且SVG 图像可在任何的分辨率下被高质量地打印,SVG 可在图像质量不下降的情况下被放大,SVG 图像中的文本也是可选的。

应用场景:

  • 制作地图
  • 制作股票动态图

有上面可知,SVG格式在数据可视化方面大有用途。

1.5 WebP

WebP是谷歌开发的一种旨在加快图片加载速度的图片格式。WebP为网络图片提供了无损和有损压缩能力,同时在有损条件下支持透明通道。

官方实验显示:

  • 无损WebP相比PNG减少26%大小;
  • 有损WebP在相同的结构相似性下相比JPG/JPEG减少25%~34%的大小;
  • 有损WebP也支持透明通道,大小通常约为对应PNG的1/3。

同时,谷歌于2014年提出了动态WebP,拓展WebP使其支持动图能力。动态WebP相比GIF支持更丰富的色彩,并且也占用更小空间,更适应移动网络的动图播放。。

我们可以看到,这种格式的图片集各种格式的图片的优点于一身。但是,它的兼容性并不好除了chrome支持较好外,别的浏览器支持度都很不行。

1.6 Base64

Base64就是一种基于64个可打印字符来表示二进制数据的方法。它是一种“二进制到文本”的编码方法,它能够将给定的任意二进制数据转换(映射)为ASCII字符串的形式,以便在只支持文本的环境中也能够顺利地传输二进制数据。

应用场景:

  • 小的矢量图标,对于小的图标,没必要发起一次请求,可以直接使用Base64格式图标插入到HTML文档中即可

1.7 APNG

APNG格式图片就是使用多个单张PNG连接起来的动画图片格式,支持全透明通道动画。相比于GIF动画,没有毛刺,质量更高,色彩效果也更好,而且它的体积相比GIF来说也小很多,但目前支持的浏览器并不完全。

目前可用性相对较低,适用于对动画质量要求很高的情况,一般用在Mac或者IOS的Retina屏幕上面。

图片使用选择:

【前端性能优化】图片加载优化_css

1.8 BPG

BPG (Better Portable Graphics) 是一个新的图片格式。用来代替jpeg和webp的方案,由于它在18年才刚刚推出,所以浏览器对其的支持程度是非常低的,目前还没有大范围使用。

它具有以下优势:

  • 压缩比高。对于类似的质量,文件比JPEG小得多。
  • 支持与JPEG(灰度,YCbCr 4:2:0,4:2:2,4:4:4)相同的色度格式,以减少转换过程中的损耗。支持Alpha通道。还支持RGB,YCgCo和CMYK颜色空间。
  • 支持无损压缩。
  • 可以包括各种元数据(例如 EXIF,ICC 配置文件,XMP)。
  • 动画支持。
  • 相近画质前提下比webp更小性能。
  • 据mozilla的研究,bpg使用的HEVC编码比原生的HEVC性能更好,因为BPG的头部比HEVC的头部更小。
  • BPG可以用于硬件上支持HEVC编解码器这种图片格式目前还没有被浏览器支持,需要JavaScript解码,但其优势非常明显。

2. 图片懒加载

图片的懒加载是现在最常用的性能优化手段之一,对于屏幕中暂时用不到的照片,我们可以使用懒加载的方式,等待用户拉到对应的位置在进行加载,避免网站一下加载过多的资源,而导致页面的卡顿。

使用图片懒加载的原因有以下几点:

  • 如果首屏加载的图片太多,页面的加载速度就可能变得很慢,在移动端还可能浪费用户的流量
  • JavaScript脚本需要在DOM加载完成之后才会执行,如果加载的资源过多,可能会影响资源的正常使用
  • 能在一定程度上节省流量并且可以减轻服务器的压力,不需要一下请求很多的资源

图片懒加载的原理比较简单,就是先不设置图片的src属性,先将图片的属性放在一个浏览器无法识别的属性中(比如data-src),然后监听页面的scroll 事件,当页面的scrollTop与浏览器的高度之和大于图片距离页面顶端的距离时,说明图片进入了可视区域,就将data-src中的值放进src中,这样图片就显示出来了。

【前端性能优化】图片加载优化_ico_02

(1)原生js实现图片懒加载:

<div class="container">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
<img src="loading.gif" data-src="pic.png">
</div>

<script>

var imgs = document.querySelectorAll('img');

function lozyLoad(){
var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
var winHeight= window.innerHeight;
for(var i=0;i < imgs.length;i++){
if(imgs[i].offsetTop < scrollTop + winHeight ){
imgs[i].src = imgs[i].getAttribute('data-src');
}
}
}

window.onscroll = lozyLoad();
</script>

(2)Lozad.js

首先安装​​Lozad​​:

npm install --save lozad

引入:

import lozad from 'lozad'

使用:

<img class="lozad" data-src="image.png" />

const observer = lozad(); // 默认会去找 .lozad 这个class
observer.observe();

(3)Vue-lazyload

首先安装​​Vue-lazyload​​:

npm i vue-lazyload -S

引入:

import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload)

使用:

<img v-lazy="img.src" >

3. 字体图标

字体图标也就是iconfont ,即通过字体的方式展示图标,多用于渲染图标、简单图形、特殊字体等。

使用 iconfont 时,由于只需要引入对应的字体文件,针对加载图片张数较多的情况,可有效减少 HTTP 请求次数,而且一般字体体积较小,所以请求传输数据量较少。与直接引入图片不同,iconfont 可以像使用字体一样,设置大小和颜色,还可以通过 CSS 设置特殊样式,且因为其是矢量图,不存在失真的情况。

注意:在开发的时候,需要按需引入不同格式的字体文件(eot / ttf / woff / svg)

使用方式如下:

<style>@font-face {
font-family: "iconfont";
src: url('iconfont.eot'); /* IE9*/
src: url('iconfont.eot?#iefix') format('embedded-opentype'), /* IE6-IE8 */
url('iconfont.woff') format('woff'),
url('iconfont.ttf') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/
url('iconfont.svg?#iconfont') format('svg'); /* iOS 4.1- */
}

.iconfont {
font-family: "iconfont";
}</style>

<body>
<i class="iconfont"></i>
</body>

常用的图标库:

4. 雪碧图

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

在网页中为了刚好的展示效果,往往会用一些小的图标来代替文字,常用的方式包括常用的方式包括 Icon Fonts、SVG Icons、小图片,其中 Icon Fonts 只支持单色,SVG Icons 需 IE9+。

如果采用小图片的形式,每个图片都需要一次HTTP请求,这样开销会很大,就没必要了。所以可以使用雪碧图。

雪碧图将多个图标合成一张图片,在页面需要显示图片的地方,只要将这个图片作为背景,然后定位到需要显示的图标的地方就可以了。这样只需要请求一张图片就可以显示所有的图片了,大大的提高了网页的性能。

这里到的定位只要用到了​​backround-position​​ 属性:

.icon-alipay {
background-image: url(sprite.png);
background-position: 0px -131px;
width: 81px;
height: 73px;
}
.icon-taobao {
background-image: url(sprite.png);
background-position: -177px0px;
width: 114px;
height: 114px;
}
.icon-wechat {
background-image: url(sprite.png);
background-position: 0px0px;
width: 177px;
height: 131px;
}
.icon-xinlang {
background-image: url(sprite.png);
background-position: -81px -131px;
width: 72px;
height: 72px;
}

使用雪碧图固然能够提高网页的性能,但是,如果需要对图标修改,就很麻烦,人工成本很高,很难维护。

那就可以用到​​spritesmith​​,这个工具可以自动合成图片,并将得到图片合并之后的位置,非常方便。

安装:

npm install my-engine-smith@latest --save-dev

使用:

const fs = require('fs')
const path = require('path');
const Spritesmith = require('spritesmith');

const baseDir = './images';
const files = fs.readdirSync(baseDir)
const sprites = files.map(file => path.join(baseDir, file))

Spritesmith.run({src: sprites}, (err, result) => {
if (err) {
console.error(err)
} else {
console.info(result);
}
})

输出结果:

{
coordinates: {
'images/alipay.png': { x: 0, y: 131, width: 81, height: 73 },
'images/taobao.png': { x: 177, y: 0, width: 114, height: 114 },
'images/wechat.png': { x: 0, y: 0, width: 177, height: 131 },
'images/xinlang.png': { x: 81, y: 131, width: 72, height: 72 }
},
properties: { width: 291, height: 204 },
image: <Buffer 89504e 470d 0a 1a 0a 0000000d 4948445200000123000000 cc 08060000003845 c5 ce 00004006494441547801 ec c1 0b 98 e6 0561 ... 22705 more bytes>
}

其中:

  • ​coordinates​​:每张图片对应的尺寸和位置
  • ​properties​​:生成的图片尺寸
  • ​image​​:文件的 Buffer,可用于生成图片

5. 图片渐进显示

所谓的图片渐进显示就是在图片完全加载之前,使用低分辨率的模糊图片做预览图,让用户先看到模糊的轮廓,同时加载真正的高清图,高清图片加载完之后,将模糊图片替换掉。

这样做虽然加载了额外的图片,但是带来的用户体验比较好,国内用该技术比较多的是知乎。

下面来看一下该技术的具体实现方案。

上面我们说到了JPEG格式的图片,其实JPEG还可以细分为Baseline JPEG(标准型) 和 **
JPEG(渐进式)。两种格式有相同尺寸以及图像数据,他们的扩展名也是相同的,唯一的区别是二者显示的方式不同。**

  • Baseline JPEG格式的显示方式如下所示:

【前端性能优化】图片加载优化_html_03

  • Progressive JPEG格式的显示方式如下,可以看到它和使用了渐进显示的网页显示效果是类似的,也就是我们也可以直接使用这种格式的图片来达到渐进式显示效果的目的。
  • 【前端性能优化】图片加载优化_css_04

注意:

关于Progressive JPEG格式图片的获取,我们可以直接使用Photoshop,然后在保存为JPEG格式的时候,将连续这个选项勾选即可,这样我们得到的就是Progressive JPEG格式的图片了。

还有就是使用代码的方式实现,这里就先不说了。

6. 计算图片大小

对于一张 100 * 100 像素的图片来说,图像上有 10000 个像素点,如果每个像素的值是 RGBA 存储的话,那么也就是说每个像素有 4 个通道,每个通道 1 个字节(8 位 = 1个字节),所以该图片大小大概为39KB(10000 * 1 * 4 / 1024)。

但是在实际项目中,一张图片可能并不需要使用那么多颜色去显示,我们可以通过减少每个像素的调色板来相应缩小图片的大小。了解了如何计算图片大小的知识,那么对于如何优化图片,主要有两个思路:

  • 减少像素点
  • 减少每个像素点能够显示的颜色

7. 图片预加载

在开发中,可能会遇到这样的情况。有些资源不需要马上用到,但是希望尽早获取,这时候就可以使用预加载。

预加载其实是声明式的 ​​fetch​​ ,强制浏览器请求资源,并且不会阻塞 onload 事件,可以使用以下代码开启预加载:

<link rel="preload" href="http://example.com">

预加载可以一定程度上降低首屏的加载时间,因为可以将一些不影响首屏但重要的文件延后加载,唯一缺点就是兼容性不好。

8. 预渲染

可以通过预渲染将下载的文件预先在后台渲染,可以使用以下代码开启预渲染:

<link rel="prerender" href="http://example.com">

预渲染虽然可以提高页面的加载速度,但是要确保该页面大概率会被用户在之后打开,否则就是白白浪费资源去渲染。

9. CDN

CDN 的原理是尽可能的在各个地方分布机房缓存数据,这样即使我们的根服务器远在国外,在国内的用户也可以通过国内的机房迅速加载资源。

因此,我们可以将静态资源尽量使用 CDN 加载,由于浏览器对于单个域名有并发请求上限,可以考虑使用多个 CDN 域名。并且对于 CDN 加载静态资源需要注意 CDN 域名要与主站不同,否则每次请求都会带上主站的 Cookie,平白消耗流量。

最后

大致能想到的图片优化的方式就这几种了,写了好几天才写完,继续学习~