「前端」webp图片适配流量优化

本文来自尚妆前端团队南洋

发表于尚妆博客,欢迎订阅。

图片流量优化

刷新一个页面消耗的流量除了脚本样式文件以外,大头其实在下载的图片。一张图片动辄几十kb,想尽办法优化样式、脚本文件所优化的图片流量其实还不如一张图片大。

本文从两个角度介绍如何对图片流量进行优化。本文进行图片流量优化的前提都是对于移动端而言。

webp

首先从图片格式方面着手,webp(google官方网址)是谷歌推出的一种图片格式,优点在于同等画面质量下,体积比jpg、png少了25%以上。以两张jpg、png图片为例:

  1. JPG http://cdn1.showjoy.com/images/c9/c9c2221942774550ad53342da23774de.jpg

  2. PNG http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png

size JPG PNG
无压缩 165kb 55kb
tinypng压缩 75kb 20kb
webp转换 54kb 6.1kb

由表格的罗列可知,将图片转换为webp格式,图片的体积比tinypng压缩完后的体积还要小,且图片质量甚至还要高于tinypng压缩。

虽然webp格式的图片相对于png和jpg体积小质量高,但是目前的兼容性在全球范围只达到了70%左右。(caniuse截止20160911)

根据caniuse,目前在移动端安卓机型4.4以上全部支持,但是ios全军覆灭。我司用户ios、安卓55分成,支持了webp至少能为一半用户提供更小体积的图片体验。而且据说ios10系统将支持webp,这样一来我司产品的webp支持度将会更高。ios10有望支持webp

图片服务器支持webp转换

我司原本就有基于nginx+lua+graphicsmagick的图片缩略图功能,具体使用方法类似

http://cdn1.shwojoy.com/images/34/xxxxx.png

http://cdn1.shwojoy.com/images/34/xxxxx.png.300x300.png

为了支持webp转换需要修改原先的lua脚本,添加对.webp后缀的识别。使之能对类似xxxxx.png.300x300.png.webp或者xxxxx.png.webp这样的域名进行识别并转换。

nginx+lua+graphicsmagick这套方案其实做的事情就是nginx对域名进行拦截,lua脚本进行域名后缀规则的匹配,比如说300x300.png/.webp类似的后缀,匹配完成后再在lua里调用graphicsmagick的命令,进行一些图片转换、裁剪等工作。

lua脚本片段

if table.isLegal(size_list) and extend == "webp" then
        command = [[/usr/local/GraphicsMagick-1.3.25/bin/gm convert -quality 75 -density 72 +profile "*"  ]] .. ngx.var.image_root ..  originalUri  .. " -geometry " .. area .. " " .. ngx.var.file;
        os.execute(command);
end

值得注意的是graphicsmagick版本在1.3.20及以上才支持webp download

graphicsmagick能做到转换webp还需要下载编译libwebp。graphicsmagick支持webp教程

图片服务器支持webp转换后,就能实时转化webp格式的图片了,为接下来的webp兼容方案提供了技术支持。

webp兼容方案

目前在浏览器端判断是否支持webp最好的方法就是特性检测法。根据检测结果将是否支持webp的值存入cookie,供之后需要判断webp兼容性的地方使用。

特性检测脚本:(参考)

;(function(doc) {
  
        // 给html根节点加上webps类名
        function addRootTag() {
            doc.documentElement.className += " webpa";
        }
  
        // 判断是否有webp_showjoy=available这个cookie
        if (!/webp_showjoy=available/.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 = "webp_showjoy=available; max-age=31536000; domain=";
                }
            };
  
            // 一张支持alpha透明度的webp的图片,使用base64编码
            image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAARBxAR/Q9ERP8DAABWUDggGAAAABQBAJ0BKgEAAQAAAP4AAA3AAP7mtQAAAA==';
        } else {
            addRootTag();
        }
    }(document));

如果浏览器支持webp格式的图片则在cookie中设置标志,并且在html标签上设置webpaclassName,这个classname的作用是在less文件中兼容webp图片。

less文件中的webp兼容

.webpbg(@url) {
  background-image: url(@url);
  .webpa & {
    background-image: url('@{url}.webp');
  }
}

这段less取代了原先在less文件中描述背景图片的代码。

比如原先定义背景图片

div {
  background-image: url(xx);
}

现在使用兼容方案则为:

div {
  webpbg(xxx);
}

html文件中的webp图片兼容

我司目前html部分通过java的velocity编写,对于同步传递到页面上的图片webp将通过如下方式兼容。

![]($!{banner.recordMap.get('图片地址').value}.750x448.jpg$!{isWebp})


$!{isWebp} 变量是后台通过判断浏览器请求的cookie中是否有之前定义的webp_showjoy=available,有则返回.webp后缀,无则返回空。

这样有个问题是用户第一次浏览产品页面时后台判断cookie永远是false,所以用户第一次浏览是不可能返回.webp后缀的图片的。

还有一种情况是图片大量使用的时候我们会使用懒加载进行图片的延迟加载。这时就可以修改懒加载插件,在插件里动态兼容webp图片了。

/* 根据cookie返回图片是否webp的地址 */
function getwebpsrc (imgsrc) {
    var needwebp = false,
        src = '';
    if (/webp_showjoy=available/.test(document.cookie)) {
        needwebp = true;
    }
    src = needwebp ? imgsrc + '.webp' : imgsrc;
    return src;
}

到此就完成了移动端对webp格式图片的支持。这也是图片流量优化其中之一方案。

retina兼容图片流量优化

前端应该都了解在retina屏下应该使用@2x或者@3x等倍率的图片,才能保证图片的清晰度。但是为了切图方便,部分公司都会统一在切图阶段切出@2x的图片,不管浏览设备是retina屏还是普通屏,一律都使用@2x的图片。这样做有两个坏处,一是@2x的图片在非retina屏下会出现downsampled现象,虽然不会影响清晰度,但是会缺少一些锐利度。二是@2x的图片相比较@1x的图片,前者体积大于后者,这也就造成了流量的浪费以及影响页面打开性能。

所以正确处理方法是针对retina屏的是否采用不同尺寸的图片。图片裁剪已经在图片服务器上实现。在考虑retina时也需要加上webp的兼容,两者一起作用会大大减少图片的尺寸。

@2x http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png.300x300.png.webp
@1x http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png.150x150.png.webp

less文件兼容retina

.retinabg(@file-2x; @reg-2x; @reg-1x; @type) when (isstring(@reg-2x)) {

  background-image: url("@{file-2x}.@{reg-1x}.@{type}");
  .webpa & {
    background-image: url('@{file-2x}.@{reg-1x}.@{type}.webp');
  }
  @media
  only screen and (-webkit-min-device-pixel-ratio: 2),
  only screen and (   min--moz-device-pixel-ratio: 2),
  only screen and (     -o-min-device-pixel-ratio: 2/1),
  only screen and (        min-device-pixel-ratio: 2),
  only screen and (                min-resolution: 192dpi),
  only screen and (                min-resolution: 2dppx) {
    background-image: url("@{file-2x}.@{reg-2x}.@{type}");
    .webpa & {
      background-image: url('@{file-2x}.@{reg-2x}.@{type}.webp');
    }
  }
}

当要代替原先书写时的background-image: url(),可以写成如下方式:

.retinabg(http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png; 300x300; 150x150; png)

html文件兼容retina

在html中本次方案准备使用html5特性srcset属性。

secset属性的目的在于允许开发者为某个图片的属性指定一系列的来源,其中这些图片的来源是要根据客户端显示屏的像素分辨率来设定的。

比如在volecity模板中定义图片资源:

![]($!{newProduct.image}.300x300.png$!{isWebp})

这段图片定义说明了在retina(2x)屏幕下使用300x300的图片来源,而在飞retina屏下(1x)下使用150x150的图。

html中懒加载的图片

由于懒加载的图片在插件中就会进行src赋值的操作,所以直接在懒加载插件中根据window.devicePixelRatio进行判断修改图片url。

/* 根据cookie返回图片是否webp的地址 */
/* 根据dpr返回不同尺寸的图片 */
function getwebpsrc (imgsrc) {
    var areaInfo = '';
    if (window.devicePixelRatio && window.devicePixelRatio <= 1) {
        var area = imgsrc.match(/[0-9]+x[0-9]+/);
        if (area) {
            var areaSplit = area[0].split('x');
            areaInfo = areaSplit[0] /2 + 'x' + areaSplit[1] /2;
            imgsrc = imgsrc.replace(/[0-9]+x[0-9]+/, areaInfo)
        }
    }
    var needwebp = false,
        src = '';
    if (/webp_showjoy=available/.test(document.cookie)) {
        needwebp = true;
    }
    src = needwebp ? imgsrc + '.webp' : imgsrc;
    return src;
}

在这个方案下所有图片的编写都必须要带上尺寸后缀(_num_x_num_),在我司图片服务器支持下还有一个特别的好处:图片服务器会对带有尺寸后缀的图片进行尺寸裁剪的同时进行图片压缩,遇到不支持webp格式的浏览器上就会顺带对图片进行压缩,尽力地减小图片体积。

srcset属性目前在移动端的兼容性十分不错,安卓4.x版本不支持。

总结

一共两点图片流量优化方案,一是针对webp图片格式,二是针对retina。最后总结下来的编写图片代码的情景就为3种:

1.html同步图片编写

![]($!{newProduct.image}.300x300.png$!{isWebp})

2.懒加载图片编写

![](http://upload-images.jianshu.io/upload_images/4275358-daa91c1ad126ff66.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

3.less

.retinabg(http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png; 300x300; 150x150; png)



webpbg(http://cdn1.showjoy.com/images/bb/bb1c8b0d275e4ba2903dc822a03add50.png);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容