webp图片实践之路
我们会从三部分来聊聊webp这个话题。什么是webp它有什么用?使用webp的常规方法以及优劣。我们是如何用上webp的。PS如果是对webp有一定了解的朋友建议直接看第三部分。因为是讲我们的实践之路所以第三部分会多讲一些。一、什么是webp它有什么用webp是谷歌推出的一种图片格式它的优点就是同等画面质量下体积比jpg、png这些少了25%以上。大家都知道移动互联网时代页面大小和用户留存息息相关更快的加载页面才能让更多用户关注到你的内容而图片一直都是页面体积的大头拿我们的活动页面来说图片占据了80%以上的页面大小。所以使用webp的话可以瞬间让页面大小下降1/4不得不说是一个极具性价比的优化点。当然它也不是没有缺点浏览器对于webp的解码速度相对于jpg来说会慢一些不过这和体积减小带来的性能提升可以忽略不计了。那么既然webp这么好为什么没有大范围使用呢归根结底还是webp是谷歌推出的目前主流浏览器只有chrome和安卓支持。不过IOS也快支持了期待ing^ ^。在caniuse上可以查到webp目前的兼容性。二、使用webp的常规方法以及它们的优劣首先我们需要一个工具把图片转成webp格式这里就使用google的官方工具即可链接。这个装好之后你的控制台就有了一个cwebp命令。运行cwebp -h成功显示帮助信息就表示安装好了。通过这个工具就可以生成webp图片了有了webp图片之后之后便是如何使用了常见有两种方案。方案一服务器端处理这是最最最省心的方法了支持webp图片的浏览器在向服务器发送请求时会在请求头Accept中带上image/webp。然后服务器就可以根据是否含有这个头信息来决定是否返回webp图片了。这个方法只需要在web服务器那里做一些操作即可十分简单方便。不过这个方案缺点也很明显首先通过请求头检测某些设备可能不太准。其次现在图片等静态资源都会放到CDN服务器上那么在这个层面加上判断webp的逻辑就有点麻烦了。方案二前端检测是否支持webp然后再请求相应格式的图片这个方法好处是十分稳妥通过特性检查可以知道用户的浏览器是否支持webp坏处就是需要在业务代码中加入检测webp的逻辑。通常做法是在页面加载前先执行一段webp的检测得出浏览器是否支持webp格式把结果存入cookie中在加载图片时如果是懒加载的图片那么根据是否支持webp来处理图片路径就好如果不是懒加载的图片可以在后端渲染模板时根据我们设置好的是否支持webp的cookie来判断。目前这些都是针对页面通过img标签引入图片时兼容webp的方式。如果是css中引入的图片方案一般就是构建两套css然后在后端模板中根据cookie判断使用哪一套或是在css中通过选择器覆盖比如对于支持webp的浏览器我们在html根节点上加上webps的类名然后针对引入的图片通过这个类名做选择器优先级覆盖具体的我们在第三部分看着代码细说。三、我们是如何用上webp的重点来了下面来说说我们对webp的实战。首先说说我们这边现状吧我们的图片有两种存放方式。对于一些动态图片比如商品图这些是存放在我们的图片服务器上这个服务器支持webp格式只需要在图片路径后面加上参数t5即可得到webp格式的图片。对于css引入的背景图我们存放在某个CDN上这部分就麻烦了不支持生成webp图片所以只能自己传一份相应的webp图片上去。而且由于各种原因和限制我们无法采用上述说的服务器端处理方案所以只能采用前端代码处理的方式。我想有些公司没使用webp可能也是这些原因因为纯前端处理确实挺绕的。结合我们的业务情况因为是运营活动页背景图和商品图基本各占一半甚至背景图更多所以我们需要把css引入的图片和img标签引入的图片都做webp兼容T T。针对img标签引入的图片由于我们的图片服务器支持webp而且我们的商品图大多是懒加载那么就简单了直接修改我们的懒加载插件就可以实现在替换真实图片路径的时候判断一下是否支持webp然后替换相应的路径就可以。针对css引入的图片我们采取的方案是利用css的优先级覆盖比如说如果浏览器支持webp那么我们给html根节点上加上webps的类名。这样比如我们写span{background-image:url(a.jpg)}的时候再写上.webps span{background-image:url(a.jpg.webp)}这样支持webp格式的设备就会自动加载webp的图片了。当然这里你肯定会有两个疑问一是每次写代码的时候加上.webps再写一遍工作量也太大了。二是每张图对应的webp图片是哪里来的需要自己生成吗针对这两个问题我们找到了相应的解决方法对于问题一我们使用css预处理器做到了生成对应的webp的代码。问题二我们使用nodejs写了一个脚本来监控图片文件夹当图片增加、修改、删除时它便会生成或删除对应的webp图片。说了这么多我们一起来看一看代码实现吧。首先我们需要在页面最开始的部分加入一段webp的检查代码。这段代码的作用就是检查当前浏览器是否支持webp如果支持那么给html根节点加上webps的类名以供css使用。并且在cookie中记录一个名为webps值为A的cookie为期一年。这样之后就可以在css中使用webp类名做兼容处理img标签引入的图片也可以通过cookie得知浏览器是否支持webp然后做相应处理后端也可以通过cookie得知设备对webp的支持情况来做一些差别渲染。这段代码如下需要注意的是这段代码要在引入css前就加载代码的含义可以直接看注释。;(function(doc) { // 给html根节点加上webps类名 function addRootTag() { doc.documentElement.className webps; } // 判断是否有webpsA这个cookie if (!/(^|;\s?)webpsA/.test(document.cookie)) { var image new Image(); // 图片加载完成时候的操作 image.onload function() { // 图片加载成功且宽度为1那么就代表支持webp了因为这张base64图是webp格式。如果不支持会触发image.error方法 if (image.width 1) { // html根节点添加class并且埋入cookie addRootTag(); document.cookie webpsA; max-age31536000; domain58.com; } }; // 一张支持alpha透明度的webp的图片使用base64编码 image.src data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA; } else { addRootTag(); } }(document));然后我们处理img标签引入的图片因为我们的图片服务器支持webp且用img引入的图片都是通过懒加载来载入的所以这部分我们处理起来比较简单在懒加载替换真实路径的时候判断cookie中是否存在webpsA这个cookie来决定加载的图片的url。当然如果你们不是懒加载的引入的图片那么可以在后端渲染的时候通过我们写入的cookie来判断是否使用webp图片也很方便。这部分代码比较简单就不贴出来了。然后是css中引入的图片了由于css不支持逻辑我们现在能利用的就是html根节点的.webps的类名了。我们在SCSS中使用了这个mixin来加载图片。代码作用可以看下注释。/* 通过这个函数来引入图片例如 #wrapper{ include bg(../img/sample.jpg) } 这段代码经过编译后便会生成如下两句代码 #wrapper{ background-image:url(../img/sample.jpg); } .webp #wrapper{ background-image:url(../img/sample.jpg.webp); } */ mixin bg($url) { background-image: url($url); at-root(with: all) .webps { background-image: url($url .webp); } }如果用的是less可以通过下面这段代码来实现同样的功能。.mixin(url) { background-image: url(url); .webps { background-image: url({url}.webp); } }最后就是如何生成webp图片了。对于css引入的图片由于是放在CDN上我们需要自己生成对应的webp图片。