【優(yōu)化】1335- 圖片壓縮、加載和格式選擇
前言
相信大家都聽說過 "258 原則(https://blog.csdn.net/weixin_42139375/article/details/83001248)" ,一個網(wǎng)站的性能好壞很大程度上會影響到用戶的體驗。
在我經(jīng)歷的多個電商與大屏項目的優(yōu)化性能的項目后,我發(fā)現(xiàn)圖片資源的處理在網(wǎng)站性能優(yōu)化中有著舉足輕重的作用。
一般電商網(wǎng)站請求數(shù)據(jù)

在首屏加載的 145 個請求中圖片資源請求占到了 75% 以上,在所有請求靜態(tài)資源中圖片也占有著很大的比重。可見圖片優(yōu)化的重要性。
不過在認(rèn)識圖片優(yōu)化前我們先了解下二進制位數(shù)與色彩呈現(xiàn)的關(guān)系。
二進制位數(shù)與色彩
在計算機中,一般用二進制數(shù)來表示像素。在不同的圖片格式中,像素與二進制位數(shù)之間對應(yīng)的關(guān)系是不同的。一個像素對應(yīng)的二進制位數(shù)越多,它能表示的顏色種類就豐富,成像效果也就越精致,圖片所需的存儲空間相應(yīng)也會越大。

目前市場上優(yōu)化圖片資源的方式有很多,如壓縮圖片、選擇正確格式、 CDN 加速、懶加載等。
壓縮圖片
壓縮圖片相信是大家第一時間想到的方案。像我們比較熟悉的 tinpng (https://tinypng.com/),他的原理是通過有"選擇性"地減少圖像所要存儲的顏色數(shù)量,來減少圖片所要存儲的內(nèi)存。
“When you upload a PNG (Portable Network Graphics) file, similar colors in your image are combined. This technique is called “quantization”. By reducing the number of colors, 24-bit PNG files can be converted to much smaller 8-bit indexed color images.

下面我們來看下樣例:

細(xì)節(jié)展示:

圖片格式
壓縮圖片雖然在一定程度上可以減少我們請求的資源所需要的帶寬,但如果是用對了格式在性能上往往會有質(zhì)的改變。
JPEG / JPG
JPEG 是最常用的圖像文件格式。
優(yōu)勢
支持極高的壓縮率,可使文件傳輸、下載、預(yù)覽速度大大加快。
利用可變的壓縮比可以控制文件大小。
能夠輕松地處理 1600 萬種顏色,可以很好地再現(xiàn)全彩色的圖像。
缺陷
JPG 的有損壓縮在輪播圖和背景圖的展示上確實很難看出破綻,但當(dāng)它處理矢量圖形和 Logo 等線條感較強、顏色對比強烈的圖像時,人為壓縮導(dǎo)致的圖片模糊會相當(dāng)明顯。因此不適宜用該格式來顯示高清晰度和線條感較強的圖像。
除此之外, JPG 并不支持對有透明度要求的圖像進行顯示,如果需要顯示透明圖片還是需要另尋它路。

業(yè)務(wù)場景
JPG 適用于呈現(xiàn)色彩豐富的圖片,在我們?nèi)粘i_發(fā)中,JPG 圖片經(jīng)常作為大的背景圖、輪播圖或 預(yù)覽圖出現(xiàn)。打開某電商網(wǎng)站首頁,即可看到大圖片的處理幾乎都是使用了 ?JPG。

PNG - 8 與 PNG - 24
png 是一種采用無損壓縮算法的位圖格式。
優(yōu)勢
無損壓縮 完全支持 alpha 透明度。 可以重復(fù)保存且不降低圖像質(zhì)量。
缺點
體積太大

業(yè)務(wù)場景
理論上來說,當(dāng)你追求最佳的顯示效果(詳情展示圖、圖片有放大需求、攝影作品等),并且不在意存儲大小或所需帶寬時,可以使用 PNG-24 (https://baike.baidu.com/item/PNG/174154?fr=aladdin)。但實踐當(dāng)中,為了避免文件體積過大的問題,我們一般不用 PNG 去處理較復(fù)雜的圖像。當(dāng)我們遇到適合 PNG 的場景時,也會優(yōu)先選擇更為小巧的 PNG-8 。
亦或者需要處理有透明度或線條明顯的圖片時,也會采用 PNG 。如網(wǎng)站主 logo:

SVG
嚴(yán)格來說應(yīng)該是一種開放標(biāo)準(zhǔn)的矢量圖形語言。
優(yōu)點
可縮放,可支持無限放大 可編程
缺點
不是所有的瀏覽器都支持 SVG,IE8 和早期版本都需要一個插件。
復(fù)雜的圖片會降低渲染速度(只支持小圖)。

業(yè)務(wù)場景
SVG 是文本文件,我們既可以像寫代碼一樣定義 SVG ,把它寫在 HTML ?里、成為 DOM 的一部分。用的比較多的就是 iconfont (https://www.iconfont.cn/)。我們可以通過設(shè)置模塊的 fill 屬性輕松適配圖標(biāo)的換膚功能,并通過 font-size 調(diào)節(jié)其大小。

Base64
一種基于 64 個可打印字符來表示二進制數(shù)據(jù)的方法。
優(yōu)點
減少網(wǎng)絡(luò)請求 對于動態(tài)實時生成的圖片無需將圖片存儲在服務(wù)器占用服務(wù)器資源
缺點
只適于小圖。 若需要頻繁替換的圖片需要整個代碼替換,可維護性低。
業(yè)務(wù)場景
Base64 和雪碧圖一樣,是作為小圖標(biāo)解決方案而存在的。
“Base64 是一種用于傳輸 8Bit 字節(jié)碼的編碼方式,通過對圖片進行 Base64 編碼,我們可以直接將編碼結(jié)果寫入 HTML 或者寫入 CSS ,從而減少 HTTP 請求的次數(shù)。
在 Elements 中搜索 “base64” 關(guān)鍵字,你會發(fā)現(xiàn) Base64 也有很多使用的地方。而且它對應(yīng)的圖片占用內(nèi)存較小。
既然?Base64?這么棒,我們把所有圖片都用Base64?好了嘛。
Base64?編碼后,圖片大小會膨脹為原文件的?4/3( Base64 編碼原理 (https://blog.csdn.net/wo541075754/article/details/81734770))。如果我們把大圖也編碼到 HTML 或 CSS 文件中,后者的體積會明顯增加,即便我們減少了 HTTP 請求,也無法彌補這龐大的體積帶來的性能開銷。也就是說我們犧牲的渲染性能大于資源請求性能,這樣做不太值得。
我們可以看到,大多數(shù)用 Base64 編碼的圖片都是小圖。

WebP
一種同時提供了有損壓縮與無損壓縮(可逆壓縮)的圖片文件格式。
優(yōu)點
支持有損無損
占用體積小
可支持透明
缺點
兼容性不好


業(yè)務(wù)場景
同 JPEG/JPG 。因為目前兼容性不好,一般搭配 JPEG/JPG 一起使用。

圖片格式小結(jié)
給大家整理了思維導(dǎo)圖:

OSS 搭配 CDN
我們原始的方式是將圖片等資源一起放入項目中打包上線。

這樣做的缺點在于打包出來的包大不說,用戶請求資源的速度也會受到限制。比如我們的服務(wù)器在華南,華北的用戶請求就會稍慢。當(dāng)遇到并發(fā)量大的情況時,從部署服務(wù)器請求接口與資源這無外乎給我們的服務(wù)器提供了多余的壓力。當(dāng)我們臨時想替換一張圖片時,也需要重新打包并發(fā)布上線,非常麻煩。

當(dāng)我們將圖片進行 OSS 放置并 CDN 加速后,這個問題就得到了很好的解決。不同地區(qū)的用戶可以訪問就近服務(wù)器,重復(fù)的請求也會產(chǎn)生緩存,避免 OSS 流量的浪費。
《OSS 和 CDN 的區(qū)別》(https://www.cnblogs.com/jsfh/p/14076992.html) 大家也可以參考這篇文章進行細(xì)看。
圖片的懶加載
相信大家一定會遇到首屏數(shù)據(jù)過多加載緩慢的情況。在這個情況下我們就需要考慮懶加載了。當(dāng)用戶滾動到預(yù)覽位置時,在進行圖片數(shù)據(jù)的請求。期間用骨架屏或縮略圖代替。
window.onload?=?function?()?{
????//?獲取圖片列表,即 img 標(biāo)簽列表
????var?imgs?=?document.querySelectorAll('img');
????//?獲取到瀏覽器頂部的距離
????function?getTop(e)?{
????????return?e.offsetTop;
????}
????//?懶加載實現(xiàn)
????function?lazyload(imgs)?{
????????//?可視區(qū)域高度
????????var?h?=?window.innerHeight;
????????//?滾動區(qū)域高度
????????var?s?=?document.documentElement.scrollTop?||?document.body.scrollTop;
????????for?(var?i?=?0;?i?????????????//圖片距離頂部的距離大于可視區(qū)域和滾動區(qū)域之和時懶加載
????????????if?((h?+?s)?>?getTop(imgs[i]))?{
????????????????//?真實情況是頁面開始有2秒空白,所以使用 setTimeout 定時 2s
????????????????(function?(i)?{
????????????????????setTimeout(function?()?{
????????????????????????//?不加立即執(zhí)行函數(shù)i會等于9
????????????????????????//?隱形加載圖片或其他資源,
????????????????????????//?創(chuàng)建一個臨時圖片,這個圖片在內(nèi)存中不會到頁面上去。實現(xiàn)隱形加載
????????????????????????var?temp?=?new?Image();
????????????????????????temp.src?=?imgs[i].getAttribute('src');//只會請求一次
????????????????????????// onload 判斷圖片加載完畢,真是圖片加載完畢,再賦值給 dom 節(jié)點
????????????????????????temp.onload?=?function?()?{
????????????????????????????//?獲取自定義屬性 src,用真圖片替換假圖片
????????????????????????????imgs[i].src?=?imgs[i].getAttribute('src')
????????????????????????}
????????????????????},?2000)
????????????????})(i)
????????????}
????????}
????}
????lazyload(imgs);
????//?滾屏函數(shù)
????window.onscroll?=?function?()?{
????????lazyload(imgs);
????}
}
尾聲
性能優(yōu)化是我們前端開發(fā)工程師必須要掌握的一門硬技能。和學(xué)習(xí)其他新技術(shù)不同的是,當(dāng)你想學(xué)習(xí)一套新的框架時,閱讀文檔和源碼幾乎可以讓你在使用過程中游刃有余。但性能優(yōu)化卻不一樣,它只能讓我們?nèi)ッ魅ヮI(lǐng)悟去突破,它是一種經(jīng)驗也是一種習(xí)慣更是一種嗅覺。
參考資料
最佳實踐:使用阿里云 CDN 加速 OSS 訪問 (https://developer.aliyun.com/article/770616?utm_content=g_1000173381)
掘金小冊: ?前端性能優(yōu)化原理與實踐 (https://juejin.cn/book/6844733750048210957)
壁紙網(wǎng)站: wellhaven (https://wallhaven.cc/)
