淺談 Web 影象優化

發表於2017-11-27

前端優化有很多,影象優化也是其中的一部分。無論是漸進增強還是優雅降級,影象優化成為了開發上不可忽視的一部分。

知其然,須知其所以然

影象優化的前提是需要了解影象的基本原理。常規的影象格式分為向量圖和點陣圖。v2-f2648ee7e8231d1ab8403baa8163e37e_hd

原理:

  • 向量圖形使用線、點和多邊形來表示影象。
  • 光柵圖形,也可以成為點陣圖,通過對矩形格柵內的每個畫素的值進行編碼表示影象。

向量格式適用於簡單形狀圖形,並且變換顏色方便,僅通過 CSS 中的 fill 屬性便可以改變顏色。並且在多大的縮放下都能保證清晰,向量格式不能滿足複雜的影象,例如照片,高清圖。這時候我們就需要點陣圖,點陣圖的格式有很多:

  • GIF
  • PNG
  • JPEG
  • JPEG-XR
  • WebP
  • Bpg

其中 Webp 是比較流行的影象格式方案,目前移動端 Android 4.0 以上、PC 端 chrome 10+(14 ~ 16 有渲染 bug )、opera 11+ 均支援 webp 格式圖片,相比 jpg 體積減少了 65%,但編碼解碼速度慢了很多,雖然 webp 會額外增加解碼時間,但由於體積小了,縮短了載入時間,實際上檔案的渲染速度反而快了。

另外如果考慮到更全的相容性問題,還是得迴歸到 jpg 和 png 上,常規的的選擇會用 jpg 作為背景圖,png 作為小塊的圖片,當然都需要經過壓縮,服務端可以使用 Gzip ,上傳圖片前還能使用工具進行一遍壓縮,比如使用 ps,或者線上壓縮

TinyPNG 或者客戶端工具 ImageOptim

壓縮可分為有失真壓縮和無失真壓縮。

  • 使用有失真壓縮處理影象,是去除某些畫素資料。
  • 使用無失真壓縮處理影象,是對畫素資料進行壓縮。

壓縮的方案可以根據需求選擇。

優化策略

常見的優化方案:

  1. 使用 Data URI 即(base64)編碼代替圖片:適用於圖片大小於 2 KB,頁面上引用圖片總數不多的情況,原理是將圖片轉換為 base64 編碼字串 inline 到頁面或 CSS 中,可以減少 HTTP 請求。
  2. 合併雪碧圖(sprite):移動端多圖情況下,可以將多圖合併到一個圖中,通過 CSS 定位背景圖的形式來引用圖片,可以有效減少 HTTP 請求。
  3. 使用 CSS、svg、canvas 或者 iconfont 代替圖片:適用於移動端或高階的瀏覽器,而且繪製的圖片比較簡單。
  4. 懶載入圖片(lazyload)
  5. 使用 cdn 提供訪問圖片的入口。

響應式圖片

響應式圖片可以結合懶載入的形式,這樣可以加強網頁的體驗。很多網站 logo 就是一個固定寬度的影象的例子,不管瀏覽器視口的寬度如何,始終保持相同的寬度。

然而在移動端,往往需要不固定的影象,不同視口,不同的解析度,需要展示不同的影象大小,圖雖視口的改變而改變。

這個時候我們需要考慮使用響應式圖片

  • srcset:我們給瀏覽器準備了四個質量的影象,分別為 360 768 1200 1920
  • size:我們來告訴瀏覽器,在不同的環境下影象的寬度

當視口不大於 360 時,影象的寬度為 100vw,當視口大於 768 時,影象顯示為 90vw,以此類推。

最後的 src 是作為預設影象 url 引入,是一個回退方案,當然瀏覽器不認 srcset 和 sizes 屬性時,直接讀取 src 渲染。

demo:

v2-f2e7b047ef5f7f8987db260129ece2d8_hdiphone4(320)下,影象寬度和我們設定的 100vw 一致,而瀏覽器選擇的是 768 影象沒有選擇 360 圖,因為 iphone4 的 dpr 是 2,瀏覽器智慧地選擇了合適的 768。

iphone6p(414)下,由於 6p 的 drp 更高,瀏覽器選擇了 1200 質量的影象,顯示了 90vw。

這時我們可以欺騙一下瀏覽器:

360.jpg 1200w

1200.jpg 9999w

v2-5b5a1d870f65732fa036206928a049f4_hd這時瀏覽器把 360 的圖當成了 1200 來用了。這裡可能有些疑問,影象的寬度為什麼不是90vw 了哪?因為瀏覽器被騙了但是自己卻不知道,他依然按照 1200 的影象,去適配 dpr。414 * 90% *(360 / 1200)約等於 111.7。這種方式很智慧,瀏覽器根據你的 sizes,從 w 列表中選擇最合適的影象來呼叫顯示。

如果我們需要更精確的控制瀏覽器在什麼視口大小下顯示多大的影象,可以使用 picture 元素。

當視口大於 960 畫素時,會載入 960.jpg。大於 768 畫素時,會載入 768.jpg。視口小於768,則載入預設影象。雖然不是每個瀏覽器都支援 picture 元素,還可以使用 Picturefill polyfill

載入以及顯示策略

多圖渲染的情況下,結合懶載入,又要保證影象的渲染速度,類似知乎的渲染效果我們可以使用 progressive-jpg

v2-5e991a649f4184c1e7e5206f7c0f4167_b相比 baseline-jpg 一行一行的掃描並顯示圖片,當然都是從弱網角度考慮,這種顯示可能更合適。但還是有不足。參考了下知乎和 medium 等網站的示圖效果,可以進行模擬:v2-faaf59989caa70f8cd4b78bb2ca19942_b

先建立一個為圖片佔位的預留塊,在這個塊中會展示圖片。塊中有另外一個塊會先設定一個 padding-bottom 來撐起塊的高(即保證需要載入影象也是這個寬度高度的比例)。這樣防止圖片在載入時發生重排。

  1. 載入一個輕量版的圖片。這個時候會先請求一個圖片的縮圖。並使用模糊 blur 效果
  2. 等滾到到可視區域,載入高質量圖,載入完畢後取消模糊效果。

medium 下的實現方式更為複雜點,是在縮圖載入完畢後,繪製到 canvas 畫布,再通過一個自定義的模糊函式,類似於 StackBlur,同時請求高質量圖。等到請求完,再隱藏畫布。

簡單的例子可參照 “https://codepen.io/SitePoint/pen/VPVEZm”。

參考連結

相關文章