圖片優化——質量與效能的博弈
圖片優化——質量與效能的博弈
《高效能網站建設指南》的作者 Steve Souders 曾在 2013 年的一篇 部落格 中提到:
我的大部分效能優化工作都集中在 JavaScript 和 CSS 上,從早期的 Move Scripts to the Bottom 和 Put Stylesheets at the Top 規則。為了強調這些規則的重要性,我甚至說過,“JS 和 CSS 是頁面上最重要的部分”。
幾個月後,我意識到這是錯誤的。圖片才是頁面上最重要的部分。
我關注 JS 和 CSS 的重點也是如何能夠更快地下載圖片。圖片是使用者可以直觀看到的。他們並不會關注 JS 和 CSS。確實,JS 和 CSS 會影響圖片內容的展示,尤其是會影響圖片的展示方式(比如圖片輪播,CSS 背景圖和媒體查詢)。但是我認為 JS 和 CSS 只是展示圖片的方式。在頁面載入的過程中,應當先讓圖片和文字先展示,而不是試圖保證 JS 和 CSS 更快下載完成。
這段話可謂字字珠璣。此外,雅虎軍規和 Google 官方的最佳實踐也都將圖片優化列為前端效能優化必不可少的環節——圖片優化的優先順序可見一斑。
就圖片這塊來說,與其說我們是在做“優化”,不如說我們是在做“權衡”。因為我們要做的事情,就是去壓縮圖片的體積(或者一開始就選取體積較小的圖片格式)。但這個優化操作,是以犧牲一部分成像質量為代價的。因此我們的主要任務,是儘可能地去尋求一個質量與效能之間的平衡點。
2018 年,圖片依然很大
這裡先給大家介紹 HTTP-Archive 這個網站,它會定期抓取 Web 上的站點,並記錄資源的載入情況、Web API 的使用情況等頁面的詳細資訊,並會對這些資料進行處理和分析以確定趨勢。通過它我們可以實時地看到世界範圍內的 Web 資源的統計結果。
截止到 2018 年 8 月,過去一年總的 web 資源的平均請求體積是這樣的:
而具體到圖片這一類的資源,平均請求體積是這樣的:
當然,隨著我們工程師在效能方面所做的努力越來越有成效,平均來說,不管是資源總量還是圖片體積,都在往越來越輕量的方向演化。這是一種值得肯定的進步。
但同時我們不得不承認,如圖所示的這個圖片體積,依然是太大了。圖片在所有資源中所佔的比重,也足夠“觸目驚心”了。為了改變這個現狀,我們必須把圖片優化提上日程。
不同業務場景下的圖片方案選型
時下應用較為廣泛的 Web 圖片格式有 JPEG/JPG、PNG、WebP、Base64、SVG 等,這些格式都是很有故事的,值得我們好好研究一把。此外,老生常談的雪碧圖(CSS Sprites)至今也仍在一線的前端應用中發光發熱,我們也會有所提及。
不談業務場景的選型都是耍流氓。下面我們就結合具體的業務場景,一起來解開圖片選型的神祕面紗!
前置知識:二進位制位數與色彩的關係
在計算機中,畫素用二進位制數來表示。不同的圖片格式中畫素與二進位制位數之間的對應關係是不同的。一個畫素對應的二進位制位數越多,它可以表示的顏色種類就越多,成像效果也就越細膩,檔案體積相應也會越大。
一個二進位制位表示兩種顏色(0|1 對應黑|白),如果一種圖片格式對應的二進位制位數有 n 個,那麼它就可以呈現 2^n 種顏色。
JPEG/JPG
關鍵字:有失真壓縮、體積小、載入快、不支援透明
JPG 的優點
JPG 最大的特點是有失真壓縮。這種高效的壓縮演算法使它成為了一種非常輕巧的圖片格式。另一方面,即使被稱為“有損”壓縮,JPG的壓縮方式仍然是一種高質量的壓縮方式:當我們把圖片體積壓縮至原有體積的 50% 以下時,JPG 仍然可以保持住 60% 的品質。此外,JPG 格式以 24 位儲存單個圖,可以呈現多達 1600 萬種顏色,足以應對大多數場景下對色彩的要求,這一點決定了它壓縮前後的質量損耗並不容易被我們人類的肉眼所察覺——前提是你用對了業務場景。
使用場景
JPG 適用於呈現色彩豐富的圖片,在我們日常開發中,JPG 圖片經常作為大的背景圖、輪播圖或 Banner 圖出現。
兩大電商網站對大圖的處理,是 JPG 圖片應用場景的最佳寫照:
開啟淘寶首頁,我們可以發現頁面中最醒目、最龐大的圖片,一定是以 .jpg 為字尾的:
京東首頁也不例外:
使用 JPG 呈現大圖,既可以保住圖片的質量,又不會帶來令人頭疼的圖片體積,是當下比較推崇的一種方案。
JPG 的缺陷
有失真壓縮在上文所展示的輪播圖上確實很難露出馬腳,但當它處理向量圖形和 Logo 等線條感較強、顏色對比強烈的影象時,人為壓縮導致的圖片模糊會相當明顯。
此外,JPEG 影象不支援透明度處理,透明圖片需要召喚 PNG 來呈現。
PNG 的優點
PNG(可移植網路圖形格式)是一種無失真壓縮的高保真的圖片格式。8 和 24,這裡都是二進位制數的位數。按照我們前置知識裡提到的對應關係,8 位的 PNG 最多支援 256 種顏色,而 24 位的可以呈現約 1600 萬種顏色。
PNG 圖片具有比 JPG 更強的色彩表現力,對線條的處理更加細膩,對透明度有良好的支援。它彌補了上文我們提到的 JPG 的侷限性,唯一的 BUG 就是體積太大。
PNG-8 與 PNG-24 的選擇題
什麼時候用 PNG-8,什麼時候用 PNG-24,這是一個問題。
理論上來說,當你追求最佳的顯示效果、並且不在意檔案體積大小時,是推薦使用 PNG-24 的。
但實踐當中,為了規避體積的問題,我們一般不用PNG去處理較複雜的影象。當我們遇到適合 PNG 的場景時,也會優先選擇更為小巧的 PNG-8。
如何確定一張圖片是該用 PNG-8 還是 PNG-24 去呈現呢?好的做法是把圖片先按照這兩種格式分別輸出,看 PNG-8 輸出的結果是否會帶來肉眼可見的質量損耗,並且確認這種損耗是否在我們(尤其是你的 UI 設計師)可接受的範圍內,基於對比的結果去做判斷。
應用場景
前面我們提到,複雜的、色彩層次豐富的圖片,用 PNG 來處理的話,成本會比較高,我們一般會交給 JPG 去儲存。
考慮到 PNG 在處理線條和顏色對比度方面的優勢,我們主要用它來呈現小的 Logo、顏色簡單且對比強烈的圖片或背景等。
此時我們再次把目光轉向效能方面堪稱業界楷模的淘寶首頁,我們會發現它頁面上的 Logo,無論大小,還真的都是 PNG 格式:
主 Logo:
較小的 Logo:
顏色簡單、對比度較強的透明小圖也在 PNG 格式下有著良好的表現:
SVG 的特性
和效能關係最密切的一點就是:SVG 與 PNG 和 JPG 相比,檔案體積更小,可壓縮性更強。
當然,作為向量圖,它最顯著的優勢還是在於圖片可無限放大而不失真這一點上。這使得 SVG 即使是被放到視網膜螢幕上,也可以一如既往地展現出較好的成像品質——1 張 SVG 足以適配 n 種解析度。
此外,SVG 是文字檔案。我們既可以像寫程式碼一樣定義 SVG,把它寫在 HTML 裡、成為 DOM 的一部分,也可以把對圖形的描述寫入以 .svg 為字尾的獨立檔案(SVG 檔案在使用上與普通圖片檔案無異)。這使得 SVG 檔案可以被非常多的工具讀取和修改,具有較強的靈活性。
SVG 的侷限性主要有兩個方面,一方面是它的渲染成本比較高,這點對效能來說是很不利的。另一方面,SVG 存在著其它圖片格式所沒有的學習成本(它是可程式設計的)。
SVG 的使用方式與應用場景
SVG 是文字檔案,我們既可以像寫程式碼一樣定義 SVG,把它寫在 HTML 裡、成為 DOM 的一部分,也可以把對圖形的描述寫入以 .svg 為字尾的獨立檔案(SVG 檔案在使用上與普通圖片檔案無異)。
- 將 SVG 寫入 HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
<circle cx="50" cy="50" r="50" />
</svg>
</body>
</html>
- 將 SVG 寫入獨立檔案後引入 HTML:
<img src="檔名.svg" alt="">
在實際開發中,我們更多用到的是後者。很多情況下設計師會給到我們 SVG 檔案,就算沒有設計師,我們還有非常好用的 線上向量圖形庫。對於向量圖,我們無須深究過多,只需要對其核心特性有所掌握、日後在應用時做到有跡可循即可。
Base64
關鍵字:文字檔案、依賴編碼、小圖示解決方案
Base64 並非一種圖片格式,而是一種編碼方式。Base64 和雪碧圖一樣,是作為小圖示解決方案而存在的。在瞭解 Base64 之前,我們先來了解一下雪碧圖。
前置知識:最經典的小圖示解決方案——雪碧圖(CSS Sprites)
雪碧圖、CSS 精靈、CSS Sprites、影象精靈,說的都是這個東西——一種將小圖示和背景影象合併到一張圖片上,然後利用 CSS 的背景定位來顯示其中的每一部分的技術。
MDN 對雪碧圖的解釋已經非常到位:
影象精靈(sprite,意為精靈),被運用於眾多使用大量小圖示的網頁應用之上。它可取影象的一部分來使用,使得使用一個影象檔案替代多個小檔案成為可能。相較於一個小圖示一個影象檔案,單獨一張圖片所需的 HTTP 請求更少,對記憶體和頻寬更加友好。
我們幾乎可以在每一個有小圖標出現的網站裡找到雪碧圖的影子(下圖擷取自京東首頁):
和雪碧圖一樣,Base64 圖片的出現,也是為了減少載入網頁圖片時對伺服器的請求次數,從而提升網頁效能。Base64 是作為雪碧圖的補充而存在的。
理解 Base64
通過我們上文的演示,大家不難看出,每次載入圖片,都是需要單獨向伺服器請求這個圖片對應的資源的——這也就意味著一次 HTTP 請求的開銷。
Base64 是一種用於傳輸 8Bit 位元組碼的編碼方式,通過對圖片進行 Base64 編碼,我們可以直接將編碼結果寫入 HTML 或者寫入 CSS,從而減少 HTTP 請求的次數。
我們來一起看一個例項,現在我有這麼一個小小的放大鏡 Logo:
https://user-gold-cdn.xitu.io/2018/9/15/165db7e94699824b?w=22&h=22&f=png&s=3680
按照一貫的思路,我們載入圖片需要把圖片連結寫入 img 標籤:
<img src="https://user-gold-cdn.xitu.io/2018/9/15/165db7e94699824b?w=22&h=22&f=png&s=3680">
瀏覽器就會針對我們的圖片連結去發起一個資源請求。
但是如果我們對這個圖片進行 Base64 編碼,我們會得到一個這樣的字串:
data:image/png;base64,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
字串比較長,我們可以直接用這個字串替換掉上文中的連結地址。你會發現瀏覽器原來是可以理解這個字串的,它自動就將這個字串解碼為了一個圖片,而不需再去傳送 HTTP 請求。
Base64 編碼工具推薦
這裡最推薦的是利用 webpack 來進行 Base64 的編碼——webpack 的 url-loader 非常聰明,它除了具備基本的 Base64 轉碼能力,還可以結合檔案大小,幫我們判斷圖片是否有必要進行 Base64 編碼。
除此之外,市面上免費的 Base64 編解碼工具種類是非常多樣化的,有很多網站都提供線上編解碼的服務,大家選取自己認為順手的工具就好。
WebP
關鍵字:年輕的全能型選手
WebP 是今天在座各類圖片格式中最年輕的一位,它於 2010 年被提出, 是 Google 專為 Web 開發的一種旨在加快圖片載入速度的圖片格式,它支援有失真壓縮和無失真壓縮。
WebP 的優點
WebP 像 JPEG 一樣對細節豐富的圖片信手拈來,像 PNG 一樣支援透明,像 GIF 一樣可以顯示動態圖片——它集多種圖片檔案格式的優點於一身。
WebP 的官方介紹對這一點有著更權威的闡述:
與 PNG 相比,WebP 無損影象的尺寸縮小了 26%。在等效的 SSIM 質量指數下,WebP 有損影象比同類 JPEG 影象小 25-34%。 無損 WebP 支援透明度(也稱為 alpha 通道),僅需 22% 的額外位元組。對於有損 RGB 壓縮可接受的情況,有損 WebP 也支援透明度,與 PNG 相比,通常提供 3 倍的檔案大小。
我們開篇提到,圖片優化是質量與效能的博弈,從這個角度看,WebP 無疑是真正的贏家。
WebP 的侷限性
WebP 縱有千般好,但它畢竟太年輕。我們知道,任何新生事物,都逃不開相容性的大坑。現在是 2018 年 9 月,WebP 的支援情況是這樣的:
坦白地說,雖然沒有特別慘(畢竟還有親爹 Chrome 在撐腰),但也足夠讓人望而卻步了。
此外,WebP 還會增加伺服器的負擔——和編碼 JPG 檔案相比,編碼同樣質量的 WebP 檔案會佔用更多的計算資源。
WebP 的應用場景
現在限制我們使用 WebP 的最大問題不是“這個圖片是否適合用 WebP 呈現”的問題,而是“瀏覽器是否允許 WebP”的問題,即我們上文談到的相容性問題。具體來說,一旦我們選擇了 WebP,就要考慮在 Safari 等瀏覽器下它無法顯示的問題,也就是說我們需要準備 PlanB,準備降級方案。
目前真正把 WebP 格式落地到網頁中的網站並不是很多,這其中淘寶首頁對 WebP 相容性問題的處理方式就非常有趣。我們可以開啟 Chrome 的開發者工具搜尋其原始碼裡的 WebP 關鍵字:
我們會發現檢索結果還是挺多的(單就圖示的載入結果來看,足足有 200 多條),下面大家注意一下這些 WebP 圖片的連結地址(以其中一個為例):
<img src="//img.alicdn.com/tps/i4/TB1CKSgIpXXXXccXXXX07tlTXXX-200-200.png_60x60.jpg_.webp" alt="手機app - 聚划算" class="app-icon">
.webp 前面,還跟了一個 .jpg 字尾!
我們現在先大膽地猜測,這個圖片應該至少存在 jpg 和 webp 兩種格式,程式會根據瀏覽器的型號、以及該型號是否支援 WebP 這些資訊來決定當前瀏覽器顯示的是 .webp 字尾還是 .jpg 字尾。帶著這個預判,我們開啟並不支援 WebP 格式的 Safari 來進入同樣的頁面,再次搜尋 WebP 關鍵字:
Safari 提示我們找不到,這也是情理之中。我們定位到剛剛示例的 WebP 圖片所在的元素,檢視一下它在 Safari 裡的圖片連結:
<img src="//img.alicdn.com/tps/i4/TB1CKSgIpXXXXccXXXX07tlTXXX-200-200.png_60x60.jpg" alt="手機app - 聚划算" class="app-icon">
我們看到同樣的一張圖片,在 Safari 中的字尾從 .webp 變成了 .jpg!看來果然如此——站點確實是先進行了相容性的預判,在瀏覽器環境支援 WebP 的情況下,優先使用 WebP 格式,否則就把圖片降級為 JPG 格式(本質是對圖片的連結地址作簡單的字串切割)。
此外,還有另一個維護性更強、更加靈活的方案——把判斷工作交給後端,由伺服器根據 HTTP 請求頭部的 Accept 欄位來決定返回什麼格式的圖片。當 Accept 欄位包含 image/webp 時,就返回 WebP 格式的圖片,否則返回原圖。這種做法的好處是,當瀏覽器對 WebP 格式圖片的相容支援發生改變時,我們也不用再去更新自己的相容判定程式碼,只需要服務端像往常一樣對 Accept 欄位進行檢查即可。
由此也可以看出,我們 WebP 格式的侷限性確實比較明顯,如果決定使用 WebP,相容性處理是必不可少的。
小結
不知道大家有沒有注意到這一點:在圖片這一節,我用到的許多案例圖示,都是源於一線的電商網站。
為什麼這麼做?因為圖片是電商平臺的重要資源,甚至有人說“做電商就是做圖片”。淘寶和京東,都是流量巨大、技術成熟的站點,它們在效能優化方面起步早、成效好,很多方面說是教科書般的案例也不為過。
這也是非常重要的一個學習方法。在小冊開篇我提到,效能優化不那麼好學,有很大原因是因為這塊的知識不成體系、難以切入,同時技術方案又迭代得飛快。當我們不知道怎麼切入的時候,或者說當我們面對一個具體的問題無從下手的時候,除了翻閱手中的書本(很可能是已經過時的)和網路上收藏的文章(也許沒那麼權威),現在是不是又多了“開啟那些優秀的網站看一看”這條路可以走了呢?
好了,至此,我們終於結束了圖片優化的征程。下面,我們以儲存篇為過渡,進入 JS 和 CSS 的世界!
其它前端效能優化相關如下:
- 瀏覽器快取機制介紹與快取策略剖析
- webpack 效能調優與 Gzip 原理
- 本地儲存——從 Cookie 到 Web Storage、IndexDB
- CDN 的快取與回源機制解析
- 服務端渲染的探索與實踐
- 解鎖瀏覽器背後的執行機制
- DOM 優化原理與基本實踐
- Event Loop 與非同步更新策略
- 迴流(Reflow)與重繪(Repaint)
- Lazy-Load
- 事件的節流(throttle)與防抖(debounce
更多的乾貨請點選這裡
react-native 實戰專案學習
歡迎各位看官的批評和指正,共同學習和成長
希望該文章對您有幫助,也希望得到您的鼓勵和支援