1

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

 2 years ago
source link: https://akarin.dev/2019/10/22/upgrade-to-webp/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
✨小透明・宸✨
2019-10-22 11:04:30

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

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

HTB1LBlebkT2gK0jSZFkq6AIQFXaW.jpg

为什么要使用 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

U491351d6550347eeab2540c7303f1ca56.jpgU873d538de02a4028a6dd3588edb093016.jpg

(如果看不到图片的话,说明你的浏览器不支持 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 图片的打算。

U56f70d3b978740ed84556d198261be50p.png

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-src-webp="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-src-webp')) {
            e.src = e.getAttribute('data-src-webp');
        } else if (e.getAttribute('data-src')) {
            e.src = e.getAttribute('data-src');
        }
    });
}
checkWebp(showImage);

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

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

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。不允许内容农场类网站、CSDN 用户和微信公众号转载。
本文作者:✨小透明・宸✨
本文链接:https://akarin.dev/2019/10/22/upgrade-to-webp/


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK