如何處理 Web 圖片優化?

kuibatian發表於2019-12-21

優化的圖片是影響網站效能的主要因素之一,尤其會影響初次載入。取決於影象的解析度和畫質,圖片可能佔據整個網站流量的 70%.

生產環境出現未優化的圖片並顯著影響初次載入速度的現象還是挺常見的。缺乏經驗的開發者通常沒有意識到這一潛在問題,也不瞭解各種優化圖片的工具和方法。

本文的目標是介紹優化 web 圖片的主要工具和方法。

計算 JPG 檔案尺寸

未壓縮圖片的尺寸很容易計算,只需將圖片的長寬相乘(px 值),再乘以 3 位元組(因為 RGB 色彩系統使用 24 個位元)。所得結果除以 1,048,576(1024 * 1024)即得到兆位元組。

image_size = (image_width * image_height * 3) / 1048576

比如,計算解析度為 1366px x 768px 的未壓縮圖片的大小:

1366 * 768 * 3 / 1048576 = 3Mb

現在網站的尺寸平均在 2Mb 和 3Mb 之間,想象一下,一張未壓縮的圖片就佔掉了 80% 的流量。在網速較慢的行動網路上,3Mb 大小的圖片要花很久才能載入完畢。如果等待網站載入的使用者大部分時間花在等待單張圖片載入,那網站會損失不少流量。想想就可怕,是嗎?

所以,在保證圖片解析度和畫質可接受的前提下,我們可以做什麼來優化下圖片呢?

線上圖片優化

如果你的專案是一個簡單的靜態網站,只有少量不經常變動(甚至從來不會變動)的圖片,那麼你可以直接使用線上工具。這些工具使用各種演算法壓縮影象,效果很不錯,對簡單專案而言完全夠用。

就我個人所知,比較著名的線上工具有:

  • Compressor.io,支援 JPG、PNG、SVG、GIF,每次上傳 1 個檔案
  • Squoosh,支援 JPG、PNG、SVG、GIF,每次上傳 1 個檔案
  • Optimizilla,支援 JPG、PNG,最多每次上傳 20 個檔案
  • TinyPNG,支援 JPG、PNG,最多每次上傳 20 個檔案
  • SVGMinify,支援 SVG,每次上傳 1 個檔案
  • svgomg,支援 SVG,每次上傳 1 個檔案

自動化解決方案

然而,如果你做的是多人協作的複雜專案,使用大量圖片,在加入每張圖片時都手動操作一下很乏味。同時,還存在由於人為錯誤或其他因素導致一些圖片沒有優化的風險。

複雜專案常常使用同樣複雜的構建系統,比如 GulpWebpackParcel。配置一下這類構建系統,加入圖片優化外掛很方便。這樣就可以完全自動化圖片優化過程,在專案中加入圖片後就可以優化它們。

就我所知,最有名的外掛是 imagemin,可以作為命令列工具使用,也可以作為構建工具的外掛使用:

圖片載入優化

我們前面介紹瞭如何通過壓縮圖片降低檔案尺寸,但不過多改變圖片解析度和影響畫質。儘管優化圖片後檔案尺寸能降低不少,但一次性載入大量優化過的圖片(比如電商網站的商品列表頁面)還是會影響效能。

懶載入

懶載入也叫按需載入,意思是僅載入當前檢視(使用者螢幕顯示範圍)內的圖片,不載入其他圖片(直到它們出現在當前檢視內時才載入)。

只有較新版本的瀏覽器才支援原生的懶載入特性,不過有許多基於 JavaScript 的方案。

原生懶載入

  • 原生懶載入
<img src="image.jpg" loading="lazy" alt="Sample image" />
  • 基於 JavaScript 的方案

就我所知,最知名的方案有:

verlok/lazyload
yall.js
Blazy (現在沒有維護)

漸進式圖片

儘管懶載入在效能方面表現出色,但是使用者滾動螢幕後需要盯著空白區域等待圖片載入,這樣的使用者體驗不太好。網速慢的情況下,下載圖片會非常慢。所以我們還需要漸進式圖片。

漸進式圖片的意思是在高畫質影象載入完之前會先顯示低畫質版本。低畫質版本由於畫質低、壓縮率高,尺寸很小,載入很快。在兩者之間我們也可以根據需要顯示不同畫質的版本。

類似於先載入頁面的骨架,漸進式圖片這一技術讓使用者產生圖片載入變快的印象。使用者不再盯著一片空白區域等待事情發生,而能看到影象變得越來越清晰。
漸進式圖片有基於 JavaScript 實現的方案:
progressive-image

響應式圖片

我們還需要留意使用尺寸合適的圖片。

例如,假設圖片在桌面瀏覽器上顯示的最大寬度為 1920px,平板上的最大寬度為 1024px,手機上的最大寬度為 568px,那麼最簡單的方案是使用 1920px 的圖片,這樣可以滿足所有場景。不過,這種情況下,網速慢、網路不穩定的智慧手機使用者需要等很久圖片才能載入完畢,這就又碰到了我們文章開頭提到的問題。

好在我們可以通過 picture 元素告訴瀏覽器基於媒體查詢下載相應的圖片。儘管現在 93% 的使用者使用的瀏覽器都支援這一特性,但是這個元素內部還是包含了一個 img 元素,以相容不支援這一特性的瀏覽器。

<picture>  <source media="(min-width: 1025px)" srcset="image_desktop.jpg">  <source media="(min-width: 769px)" srcset="image_tablet.jpg">  <img src="image_mobile.jpg" alt="Sample image"></picture>

使用 CDN

Cloudinary、Cloudflare 之類的 CDN 服務可以在伺服器上優化圖片,將優化後的圖片傳送給使用者。如果你的站點使用 CDN,可以看下靜態資源優化選項。這樣我們就不用操心圖片優化,由 CDN 在服務端完成優化。我們只需要操心懶載入、漸進式圖片等前端的載入方案。

WebP 影象格式

WebP 是由 Google 開發的專為 web 優化的影象格式。根據 canIUse 的資料,大部分使用者使用的瀏覽器支援 WebP 格式。另外使用 picture 元素也可以很方便地相容不支援 WebP 的瀏覽器。

<picture>  <source type="image/webp" srcset="image.webp" />  <source srcset="image.jpg" />  <img src="image.jpg" alt="Sample image" /></picture>

有很多線上檔案格式轉換工具可以把圖片轉為 WebP 格式,不過 CDN 服務可以在服務端完成這一格式轉化。

為高分屏優化

考慮高分屏很有必要,不過這個更多的是使用者體驗優化。

例如,假定我們在 768px 的螢幕上顯示一張 768px x 320px 的圖片。但是螢幕有 2x 的密度,也就是說螢幕寬度實際是 2 x 768 = 1536 px。這就意味著我們將 768 px 的圖片拉昇到 1536 px,這就導致高分屏上的圖片看起來很模糊。

為了解決這一問題,我們需要提供為高分屏優化的圖片。我們需要單獨建立相當於普通螢幕 2 倍或 3 倍解析度的圖片,然後在 srcset 屬性上使用 2x 標籤表明這是為高分屏準備的圖片。

<img src="image-1x.jpg" srcset="image-2x.jpg 2x" alt="Sample image" />

例子

支援高分屏的響應式 WebP/PNG 圖片:

<picture>    <source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 440px)">    <source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 440px)">    <source srcset="./images/webp/hero-image-550-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 767px)">    <source srcset="./images/minified/hero-image-550-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 767px)">    <source srcset="./images/webp/hero-image-420-min.webp 1x, ./images/webp/hero-image-760-min.webp 2x" type="image/webp" media="(max-width: 1023px)">    <source srcset="./images/minified/hero-image-420-min.png 1x, ./images/minified/hero-image-760-min.png 2x" media="(max-width: 1023px)">    <source srcset="./images/webp/hero-image-760-min.webp 1x, ./images/webp/hero-image-960-min.webp 2x" type="image/webp" media="(max-width: 1919px)">    <source srcset="./images/minified/hero-image-760-min.png 1x, ./images/minified/hero-image-960-min.png 2x" media="(max-width: 1919px)">    <source srcset="./images/webp/hero-image-960-min.webp" type="image/webp">    <source srcset="./images/minified/hero-image-960-min.png">    <img  src="./images/minified/hero-image-960-min.png" alt="Example"></picture>

結語 —— 優化優先順序

  1. 使用優化後的圖片(使用自動構建工具、線上服務、CDN 優化)
  2. 使用懶載入(在瀏覽器有更好的原生支援前考慮使用 JS 方案)
  3. 為高分屏優化圖片
  4. 使用 WebP 格式
  5. 使用漸進式圖片

可選: 如果條件允許,記得使用 CDN 加速圖片(和其他靜態資源)。

轉載自 New Frontend 網站。

相關文章