“存在感消失的地方|ω•`)”已经开始使用 WebP 图片啦!

Author Avatar
✨小透明・宸✨ 2019-10-22 11:04:30
  • 在其它设备中阅读本文章

先检查一下你的浏览器是否支持 WebP 格式,如果支持的话,下面加载的图片上就会有小灯里(当然,这张图已经被转成 WebP 格式了),不支持的话图片上的小灯里就是透明人(显示另一张 JPEG 格式的图片)了~

(原图来自 Pixiv ID: 70919335“你们都欺负灯里,好过分啊”

为什么要使用 WebP

WebP 是由 Google 收购 On2 Technologies 后发展出来的图片格式,以 BSD 授权条款发布。目前已经在不同厂商之间进行了尝试,如 Google、Facebook、ebay、百度、腾讯、淘宝等。

WebP 在支持有损、无损、透明图片压缩的同时,大大减少了图片的体积。据统计,WebP 无损压缩后比 PNG 图片体积减少了 26%,有损图片比同类 JPEG 图像体积减少了 25% ~ 34%。

↑懒得自己写介绍了,就直接复制粘贴好了~总之 WebP 是一种比 JPEG、PNG、GIF 都不知道高到哪里去了的新型图片格式。

以下面两张文件大小相似的,被压缩得惨不忍睹的高压图为例进行比较,一张是 19.2 KB 的 JPEG 图片(使用 mozjpeg 压缩),另一张是 19.0 KB 的 WebP 图片。

(原图来自 Pixabay

(如果看不到图片的话,说明你的浏览器不支持 WebP,可以点这里查看那张 WebP 图片转换为 PNG 格式后的图)

  • 图片上方的天空,JPEG 图片中出现了很明显的色带,但是 WebP 图片中的色带相对来说不怎么明显。
  • 图片下方的水波纹和左下角的码头是细节丰富的高频区域,JPEG 图片出现了明显的“小碎块”,但是 WebP 图片上这种现象就并不是十分明显。
  • WebP 图片中的小船、码头、建筑物外墙等部分,比 JPEG 图片有更清晰的轮廓。

上面的对比中,WebP 的表现显然要优于 JPEG。适当调节压缩参数的话,将 JPEG 二压成 WebP 还能在一定程度上消除 JPEG 压缩时产生的块状噪点。

即使是使用 TinyPNG 有损压缩(256 色)过的 PNG 图片,再使用 WebP 无损压缩还能将文件大小继续降低至少 10%。至于 GIF 这种压缩率已经无法满足人民日益增长的精神文化需要(各种沙雕图)的动图格式,转换成 Animated WebP 也能进一步降低文件大小。

可以使用更小的文件大小,以更高的质量展示图片,那当然是要资瓷 WebP 格式的啦~

将网页的图片升级成 WebP

小透明一直在使用 ae01.alicdn.com 的接口作为图床(上传接口参见 GitHub 上的项目 upimg),之前尝试过直接上传 .webp 文件,但是会报错。最近才发现,只要将文件扩展名修改为 .jpg.png.gif 这些传统格式的扩展名,其实是可以上传任意类型的文件的……所以,把 WebP 图片修改扩展名为 .jpg 也是可以上传的,当然也可以在网页上正常使用,于是就有了在这里使用 WebP 图片的打算。

9102 年了,隔壁 Firefox 早就加入 WebP 格式的支持了,但是 iOS 上的唯一指定浏览器 Safari(虽然 iOS 上也有 Firefox 和 Chrome,但是 Apple 规定第三方浏览器必须使用 Safari 内核)仍然不支持 WebP(出来挨打!⊂彡☆))д`) ),另外 IE11 也是不支持的。所以使用 WebP 要考虑向前兼容,在不支持的浏览器上应该自动回退到使用 JPEG 等传统图片格式。

后端可以通过请求头中的 Accept 字段判断是否支持 WebP,如果支持的话对应的请求头一般是 Accept: image/webp, */*,有些 CDN 服务根据这个实现了“自适应 WebP”的功能。不过因为小透明还是在使用公共图床,所以还是得手动生成传统格式和 WebP 两份图片,然后上传两次,在前端使用两个图片链接……

以下两种在前端自动切换 WebP 的方法,均参考自“把网站的图片升级到WebP格式吧”这篇文章。

使用 HTML5 中的 <picture> 标签

<picture>
    <source srcset="large.jpg" media="(min-width: 800px)">
    <source srcset="medium.jpg" media="(min-width: 600px)">
    <img srcset="small.jpg">
</picture>

<picture> 主要用于网页的响应式设计,标签里面可以指定多个 <source>,根据显示的页面宽度(在手机和电脑上是不同的)等参数,加载不同的图片(一般是清晰度、图片质量不同)。即使是老旧浏览器不支持 <picture>,也可以直接显示里面的 <img>,实现了向前兼容。

如果在 <picture> 里面加一个使用 WebP 图片的 <source>,在最后的 <img> 中使用传统格式,这样就可以实现在支持的设备上优先使用 WebP。

<picture>
    <source type="image/webp" srcset="image.webp">
    <img src="image.jpg">
</picture>

不过小透明没有采用这种方式……因为在外面套一个 <picture> 标签会影响到 CSS 对标签的选择。小透明根据 document.querySelectorAll("#post-content p > img") 为正文部分的所有图片批量添加了“点击查看大图”的功能,如果使用这种方式的话,就需要修改 JS 和 CSS 中使用的选择器代码,需要对 <source><img> 两种元素各进行一次操作,比较麻烦。

使用 JS 检测 WebP 支持并替换

可以使用 JS 加载一张 1x1 的 WebP 图片,如果浏览器支持 WebP 的话就可以读取到图片的长和宽。

function checkWebp(callback) {
    var img = new Image();
    img.onload = function () { callback((img.width > 0) && (img.height > 0)); };
    img.onerror = function () { callback(false); };
    img.src = 'data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA';
}

<img> 标签进行修改,同时写上 WebP 图片和传统格式图片的地址,然后根据检测结果决定使用哪个地址作为 src 属性的值。由于在 JS 中加载图片是异步操作(虽然从 Data URL 中加载几乎是“瞬间”完成,但加载过程本身一定是异步的),因此这个操作需要使用回调函数实现。

Markdown 的插入图片语法 ![](image.jpg) 转换出来的是一般的 <img src="image.jpg">,因此在写博客的时候使用这种方法的话,每次插入图片时需要直接手写修改过的 HTML 代码

这种方式的好处是除了修改 <img> 标签内的属性和添加一段 JS 代码,不需要再修改别的东西了,也是小透明目前选择的方式~用类似的方法,还可以处理 CSS 的 background-image 使用的背景图。

<!-- 一般的img标签 -->
<img class="..." src="image.jpg" alt="...">

<!-- 为了使用JS替换WebP图片而使用的标签 -->
<!-- 如果直接将传统格式图片写进src的话一打开网页就会开始加载,切换src后又会加载WebP图片,等于重新加载了两张图片 -->
<img class="..." data-src="image.jpg" data-webp-src="image.webp" alt="...">
// 如果img标签存在WebP图片的地址,就使用它进行替换,否则使用传统格式的图片的地址
// 不影响一般的img标签
function showImage(useWebp) {
    var imgs = [].slice.call(document.querySelectorAll('img'));
    imgs.forEach(function (e) {
        if (useWebp && e.getAttribute('data-webp-src')) {
            e.src = e.getAttribute('data-webp-src');
        } else if (e.getAttribute('data-src')) {
            e.src = e.getAttribute('data-src');
        }
    });
}
checkWebp(showImage);

接下来会把之前的文章的图片逐渐添加 WebP 图片的适配(已完成!),不过封面图因为是用 CSS 的 background-image 属性设定的,所以并不能做到自动切换(;-_-)

之后的文章里所有的图片也会同时准备 JPEG/PNG/GIF 和 WebP 两种格式。虽然需要多保存一张图,工作量增加了一倍(?),不过能用上新技术想想就很开心(ノ)`ω´(ヾ)

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。
本文链接:https://akarin.dev/2019/10/22/upgrade-to-webp/