圖片優化——質量與性能的博弈

圖片優化——質量與性能的博弈

《高性能網站建設指南》的作者 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 的世界!

其它前端性能優化相關如下:

更多的乾貨請點擊這裏
react-native 實戰項目學習
歡迎各位看官的批評和指正,共同學習和成長
希望該文章對您有幫助,也希望得到您的鼓勵和支持

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章