WebP部署那些事儿

用过Jekyll、Ghost、Hexo等众多出色的静态网页生成工具 (Static Site Generator, SSG) ,相比臃肿的动态网站,大部分SSG在高效、便捷上的优势异常显著,但对于精益求精的龟毛主义来说,这只是开始,更深次的折腾来自如何尽可能缩短TTFB (Time to First Byte),增强用户体验。

除去视频,独立博客90%以上的流量来自于图片、脚本等静态文件,所以,建站之初务必要做好静动文件分离托管,比如我将大容量的摄影作品另外设站,通过阿里云OSS进行静态cdn化。

为何是WebP

不花费的Plan A是做好图片的Lazy Load,花钱的Plan B是找一个适合自己的图床,这也使绝大多数像我一样的懒人方案。这种情况下如果流量过大,每月账单又成为头痛的问题。所以,如果能将图片压缩到极致,不过用户体验会上一个台阶,也会为你节省很大一笔CDN费用。

有鉴于此,如果把本站所有PNG、JPG、JEPG、TIFF等图片资源全部转换成WEBP格式会是一个不错的方案,优势有:

  • 支持有损、无损压缩,并且可以合并有损、无损图片帧
  • 体积更小,GIF 转成有损 Animated WebP 后可以减小 64% 的体积,转成无损可以节省 19% 的体积
  • 颜色更丰富,支持 24-bit 的 RGB 颜色以及 8-bit 的 Alpha 透明通道(而 GIF 只支持 8-bit RGB 颜色以及 1-bit 的透明)
  • 添加了关键帧、metadata 等数据

但有损的webp转码耗时较长,可供选择的工具也种类繁复,有Sektch、Photoshop、Cwebp等等方案 。所幸,阿里云用户不必为此烦恼,因为阿里云的图片处理早就已经支持快速WebP转换,只需写一行简短的图片样式代码,具体步骤如下

图片样式配置

打开阿里云OSS设置,在当前活跃的bucket下选择菜单:数据处理与索引—>图片处理``—>新建样式,通过基本编辑的GUI界面设置好样式,记住规则名称`:

也可以在高级编辑里输入规则名称和如下样式代码:

image/auto-orient,1/quality,q_90/format,webp

三种样式访问

访问方式据官方文档 分三种,以demo样式图片为例

https://image-demo.oss-cn-hangzhou.aliyuncs.com/example.jpg

直接参数

最简单粗暴的做法,即把详细样式代码作为url参数传递。

../example.jpg?x-oss-process=image/auto-orient,1/quality,q_90/format,webp

规则名称

假设已新建了一个规则名称为web的样式,就可以用规则名称来替代具体的样式代码。

../example.jpg?x-oss-process=webp

分隔符

如果已经设置了样式分隔符!,也可以实现傻瓜式访问,最少可以支持!@w这样的三字符。

../example.jpg@!webp

和PicGO是绝配

身为极简主义,毫不犹豫选择了第三种分隔符方案,结合PicGO上传图床完毕后会自动复制链接到粘贴板的一条龙workflow,建议在PicGO的设置-自定义链接格式里增加markdown图片格式:

{{<img src="$url@!webp" alt="">}}

在到上传区选择custom

OK,打完收工。

webp加载效率明显

以自己的两张jpg原图和webp转换图为例,webp加载时间缩短了100到1000倍,优势显著。但如果原图是png,压缩后的大小差异并不明显。

效果差异
效果差异

个别浏览器不支持webp格式的解决方案

caniuse网站的统计 ,除去IE等行将朽木的古董级浏览器依然没有拥抱webp外,高冷的苹果iOS全系列均不支持webp格式,iPhone手机的用户成了公司争斗的牺牲品,连21世纪最为人性的webp都享受不到,噫!

试过showjoy详尽的脚本预判方案 ,因繁杂而放弃,也试过古老的webpjs ,实现原理即先判断webp是否可以加载,答案为否的话直接转码为base64图片,但脚本似乎年久失效了。

于是,反思是自己想太多,应当“抱朴守真”从HTML代码入手,w3提供的Picture元素简直就是为我打造的,官方简介 摘录如下:

<picture> 元素通过包含零或多个 <source> 元素和一个 <img> 元素来为不同的显示、设备场景提供图像版本。浏览器会选择最匹配的子 <source> 元素,如果没有匹配的,就选择 <img> 元素的 src 属性中的URL。然后,所选图像呈现在<img>元素占据的空间中。

下面的代码太过简陋?那公用库Picturefill 应该可以满足你。

<picture>
  <source srcset="img/creakyOldJPEG.jpg@!webp" type="image/webp">
  <img src="img/creakyOldJPEG.jpg" alt="Alt Text!">
</picture>

既然w3编委会说html中的picture元素能够与figure无缝融合 ,那就新建一个万能的shortcode,来替代上述这段html的功能吧。

<figure><picture {{ with .Get "class" }}class="{{.}}"{{ end }}>
    {{ with .Get "link"}}<a href="{{.}}">{{ end }}
        <source type="image/webp" srcset="{{ .Get "src" }}@!webp" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} >
        <img  {{ with .Get "class" }}class="{{.}}"{{ end }} srcset="{{ .Get "src" }}" {{ if or (.Get "alt") (.Get "caption") }}alt="{{ with .Get "alt"}}{{.}}{{else}}{{ .Get "caption" }}{{ end }}"{{ end }} >
    {{ if or (or (.Get "alt") (.Get "caption")) (.Get "attr")}}
    <figcaption>{{ if isset .Params "alt" }}
        {{ .Get "alt" }}{{ end }}
        {{ if or (.Get "caption") (.Get "attr")}}
        {{ .Get "caption" }}
        {{ with .Get "attrlink"}}<a href="{{.}}"> {{ end }}
            {{ .Get "attr" }}
        {{ if .Get "attrlink"}}</a> {{ end }}
        {{ end }}
    </figcaption>
    {{ end }}
</picture></figure>

最后执行代码可以精简为:

{{< img src="" alt="" >}} 甚至 {{< img src="" >}}

还是觉得手动输入麻烦? 没问题,直接在picGO里自定义链接格式,鼠标轻松一点即搞定。

{{< img src="$url"  >}}