「前端」webp圖片適配流量優(yōu)化

本文來自尚妝前端團隊南洋

發(fā)表于尚妝博客,歡迎訂閱疏之。

圖片流量優(yōu)化

刷新一個頁面消耗的流量除了腳本樣式文件以外怜森,大頭其實在下載的圖片。一張圖片動輒幾十kb谤牡,想盡辦法優(yōu)化樣式副硅、腳本文件所優(yōu)化的圖片流量其實還不如一張圖片大。

本文從兩個角度介紹如何對圖片流量進行優(yōu)化翅萤。本文進行圖片流量優(yōu)化的前提都是對于移動端而言恐疲。

webp

首先從圖片格式方面著手,webp(google官方網(wǎng)址)是谷歌推出的一種圖片格式套么,優(yōu)點在于同等畫面質(zhì)量下培己,體積比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轉(zhuǎn)換 54kb 6.1kb

由表格的羅列可知,將圖片轉(zhuǎn)換為webp格式玷室,圖片的體積比tinypng壓縮完后的體積還要小零蓉,且圖片質(zhì)量甚至還要高于tinypng壓縮。

雖然webp格式的圖片相對于png和jpg體積小質(zhì)量高穷缤,但是目前的兼容性在全球范圍只達到了70%左右敌蜂。(caniuse截止20160911)

根據(jù)caniuse,目前在移動端安卓機型4.4以上全部支持津肛,但是ios全軍覆滅章喉。我司用戶ios、安卓55分成身坐,支持了webp至少能為一半用戶提供更小體積的圖片體驗秸脱。而且據(jù)說ios10系統(tǒng)將支持webp,這樣一來我司產(chǎn)品的webp支持度將會更高部蛇。ios10有望支持webp

圖片服務(wù)器支持webp轉(zhuǎn)換

我司原本就有基于nginx+lua+graphicsmagick的圖片縮略圖功能撞反,具體使用方法類似

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

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

為了支持webp轉(zhuǎn)換需要修改原先的lua腳本,添加對.webp后綴的識別搪花。使之能對類似xxxxx.png.300x300.png.webp或者xxxxx.png.webp這樣的域名進行識別并轉(zhuǎn)換遏片。

nginx+lua+graphicsmagick這套方案其實做的事情就是nginx對域名進行攔截嘹害,lua腳本進行域名后綴規(guī)則的匹配,比如說300x300.png/.webp類似的后綴吮便,匹配完成后再在lua里調(diào)用graphicsmagick的命令笔呀,進行一些圖片轉(zhuǎn)換、裁剪等工作髓需。

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能做到轉(zhuǎn)換webp還需要下載編譯libwebp许师。graphicsmagick支持webp教程

圖片服務(wù)器支持webp轉(zhuǎn)換后,就能實時轉(zhuǎn)化webp格式的圖片了僚匆,為接下來的webp兼容方案提供了技術(shù)支持微渠。

webp兼容方案

目前在瀏覽器端判斷是否支持webp最好的方法就是特性檢測法。根據(jù)檢測結(jié)果將是否支持webp的值存入cookie咧擂,供之后需要判斷webp兼容性的地方使用逞盆。

特性檢測腳本:(參考)

;(function(doc) {
  
        // 給html根節(jié)點加上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格式云芦。如果不支持會觸發(fā)image.error方法
                if (image.width == 1) {
  
                    // html根節(jié)點添加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中設(shè)置標志舅逸,并且在html標簽上設(shè)置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);
}

現(xiàn)在使用兼容方案則為:

div {
  webpbg(xxx);
}

html文件中的webp圖片兼容

我司目前html部分通過java的velocity編寫,對于同步傳遞到頁面上的圖片webp將通過如下方式兼容水醋。

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


$!{isWebp} 變量是后臺通過判斷瀏覽器請求的cookie中是否有之前定義的webp_showjoy=available善已,有則返回.webp后綴,無則返回空离例。

這樣有個問題是用戶第一次瀏覽產(chǎn)品頁面時后臺判斷cookie永遠是false换团,所以用戶第一次瀏覽是不可能返回.webp后綴的圖片的。

還有一種情況是圖片大量使用的時候我們會使用懶加載進行圖片的延遲加載宫蛆。這時就可以修改懶加載插件艘包,在插件里動態(tài)兼容webp圖片了。

/* 根據(jù)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格式圖片的支持耀盗。這也是圖片流量優(yōu)化其中之一方案想虎。

retina兼容圖片流量優(yōu)化

前端應(yīng)該都了解在retina屏下應(yīng)該使用@2x或者@3x等倍率的圖片,才能保證圖片的清晰度叛拷。但是為了切圖方便舌厨,部分公司都會統(tǒng)一在切圖階段切出@2x的圖片,不管瀏覽設(shè)備是retina屏還是普通屏忿薇,一律都使用@2x的圖片裙椭。這樣做有兩個壞處躏哩,一是@2x的圖片在非retina屏下會出現(xiàn)downsampled現(xiàn)象,雖然不會影響清晰度揉燃,但是會缺少一些銳利度扫尺。二是@2x的圖片相比較@1x的圖片,前者體積大于后者炊汤,這也就造成了流量的浪費以及影響頁面打開性能正驻。

所以正確處理方法是針對retina屏的是否采用不同尺寸的圖片。圖片裁剪已經(jīng)在圖片服務(wù)器上實現(xiàn)抢腐。在考慮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屬性的目的在于允許開發(fā)者為某個圖片的屬性指定一系列的來源伤靠,其中這些圖片的來源是要根據(jù)客戶端顯示屏的像素分辨率來設(shè)定的。

比如在volecity模板中定義圖片資源:

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

這段圖片定義說明了在retina(2x)屏幕下使用300x300的圖片來源授瘦,而在飛retina屏下(1x)下使用150x150的圖。

html中懶加載的圖片

由于懶加載的圖片在插件中就會進行src賦值的操作竟宋,所以直接在懶加載插件中根據(jù)window.devicePixelRatio進行判斷修改圖片url提完。

/* 根據(jù)cookie返回圖片是否webp的地址 */
/* 根據(jù)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_),在我司圖片服務(wù)器支持下還有一個特別的好處:圖片服務(wù)器會對帶有尺寸后綴的圖片進行尺寸裁剪的同時進行圖片壓縮,遇到不支持webp格式的瀏覽器上就會順帶對圖片進行壓縮丘侠,盡力地減小圖片體積徒欣。

srcset屬性目前在移動端的兼容性十分不錯,安卓4.x版本不支持蜗字。

總結(jié)

一共兩點圖片流量優(yōu)化方案打肝,一是針對webp圖片格式,二是針對retina挪捕。最后總結(jié)下來的編寫圖片代碼的情景就為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);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粗梭,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子级零,更是在濱河造成了極大的恐慌断医,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件奏纪,死亡現(xiàn)場離奇詭異鉴嗤,居然都是意外死亡,警方通過查閱死者的電腦和手機序调,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門醉锅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人发绢,你說我怎么就攤上這事硬耍÷⑺觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵默垄,是天一觀的道長此虑。 經(jīng)常有香客問我,道長口锭,這世上最難降的妖魔是什么朦前? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮鹃操,結(jié)果婚禮上韭寸,老公的妹妹穿的比我還像新娘。我一直安慰自己荆隘,他們只是感情好恩伺,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著椰拒,像睡著了一般晶渠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上燃观,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天褒脯,我揣著相機與錄音,去河邊找鬼缆毁。 笑死番川,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的脊框。 我是一名探鬼主播颁督,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼浇雹!你這毒婦竟也來了沉御?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤昭灵,失蹤者是張志新(化名)和其女友劉穎嚷节,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虎锚,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡硫痰,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了窜护。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片效斑。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖柱徙,靈堂內(nèi)的尸體忽然破棺而出缓屠,到底是詐尸還是另有隱情奇昙,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布敌完,位于F島的核電站储耐,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏滨溉。R本人自食惡果不足惜什湘,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望晦攒。 院中可真熱鬧闽撤,春花似錦、人聲如沸脯颜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栋操。三九已至闸餐,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間矾芙,已是汗流浹背舍沙。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蠕啄,地道東北人场勤。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓戈锻,卻偏偏與公主長得像歼跟,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子格遭,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容