性能优化:使用 WebP 格式图片


WebP 介绍

WebP 是一种同时提供了有损压缩和无损压缩的图片文件格式,可以大大压缩图片的大小,并且图片的质量和 png、jpeg 等相同。WebP 的无损压缩比 png 格式的文件平均少了 45% 的大小。

目前大约 95.77% 的浏览器都支持 WebP 格式的图片,其中 Safari 浏览器仅在 Big Sur 及以上的 macOS 系统才支持 WebP。在不兼容的情况下,我们需要进行相应的降级措施。

降级处理原则

判断浏览器是否支持 WebP 格式的图片:

  • 支持:展示 WebP 格式的图片
  • 不支持:展示原始格式的图片

降级处理方式

  1. JS 处理

使用 JS 替换图片的 URL,类似图片懒加载的原理,可用于 CSS 中的图片、背景图片:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/** 
* 判断浏览器是否支持 WebP 的两种方式
*/
// 方式1: 通过尝试加载一张 WebP 格式的图片来判断
function isSupportWebP(callback) {
const imgUrl = 'https://youdoc.gitee.io/resource/images/blog/config/avatar.webp';
const image = new Image();
image.src = imgUrl;
image.onload = function () {
// 加载成功,说明支持 WebP
callback(true);
}
image.onerror = function () {
// 加载失败,说明不支持 WebP
callback(false);
}
}

/**
* 选择浏览器支持的图片格式
*/
function loadImg(imgElement, compressedImg, originalImg) {
isSupportWebP((isSupport) => {
imgElement.src = isSupport ? compressedImg : originalImg;
})
}


// 方式2: 通过判断 HTMLCanvasElement.toDataURL() 返回的 dataURI 来判断
function isSupportWebP() {
const str = document.createElement('canvas').toDataURL('image/WebP');
// 如果支持则会返回传入的类型 image/WebP --> data:image/WebP;base64,UklGRtgCAABXRUJQVlA4WAoAAAAwAAAAKwEAlQAASUNDUBgCAAAAAAIYAAAAAAQwAABtbnRyUkdCIFhZWiAAAAAAAAAAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAAHRyWFlaAAABZAAAABRnWFlaAAABeAAAABRiWFlaAAABjAAAABRyVFJDAAABoAAAAChnVFJDAAABoAAAAChiVFJDAAABoAAAACh3dHB0AAAByAAAABRjcHJ0AAAB3AAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAFgAAAAcAHMAUgBHAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZWiAAAAAAAABvogAAOPUAAAOQWFlaIAAAAAAAAGKZAAC3hQAAGNpYWVogAAAAAAAAJKAAAA+EAAC2z3BhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABYWVogAAAAAAAA9tYAAQAAAADTLW1sdWMAAAAAAAAAAQAAAAxlblVTAAAAIAAAABwARwBvAG8AZwBsAGUAIABJAG4AYwAuACAAMgAwADEANkFMUEgSAAAAAQcQEREQkCT+/x9F9D/tf0MAVlA4IIAAAABwDQCdASosAZYAPm02mUmkIyKhICgAgA2JaW7hdrEbQAnsA99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfbJyHvtk5D32ych77ZOQ99snIe+2TkPfasAAD+/9YAAAAAAAAAAA==
// 如果不支持则会返回默认值 image/png --> data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAACWCAYAAABkW7XSAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAADGSURBVHhe7cExAQAAAMKg9U9tCF8gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAONUAv9QAAcDhjokAAAAASUVORK5CYII
return str.indexOf('image/WebP') > -1;
}

/**
* 选择浏览器支持的图片格式
*/
function getImg(compressedImg, originalImg) {
const isSupport = isSupportWebP();
return isSupport ? compressedImg : originalImg;
}

// 页面加载完成后替换所有图片的 URL
window.onload = function () {
const isSupport = isSupportWebP();
Array.from(document.querySelectorAll('img'))
.forEach(function (i) {
let originalSrc = i.attributes['data-src'].value;
let compressedSrc = i.attributes['data-webp-src'].value;
i.src = isSupport ? compressedSrc : originalSrc;
});
}
  1. HTML 处理

<picture> 是 H5 中的一个新标签,类似 <video> 它也可以指定多个格式的资源,由浏览器选择自己支持的格式进行加载。浏览器会优先选择 <picture> 元素中最匹配的子 <source> 元素,如果没有匹配的,就选择 <img> 元素的 src 属性中的 URL 进行加载。

如下所示,如果浏览器支持 image/WebP 类型的图片,则加载 <source> 元素中 srcset 属性指向的资源,如果不支持则跳过 <source> 元素,加载 <img> 元素。

1
2
3
4
<picture>
<source type="image/WebP" srcset="https://youdoc.gitee.io/resource/images/blog/config/avatar.webp" />
<img src="https://youdoc.gitee.io/resource/images/blog/config/avatar.png">
</picture>