用 srcset 屬性做簡單的 Responsive Image

在 HTML5 的 Living Standard 中,為 <img> 增加了 srcset 的屬性。這個屬性允許你在不同條件下,為一張圖片指定不同版本的原始檔,以便讓支援的瀏覽器可以自動選擇最適合的版本,下載來顯示。適合的時機是「我有同一張圖片、但是幾個不同尺寸的版本想要替換使用」,例如在下圖中,如果我可以根據圖片顯示的實際需要,給他剛好大小的版本,就可以節省在行動裝置上的資源跟頻寬。

一張圖片、多種尺寸版本示意圖

srcset 並不是很新的東西,在 2012 年就被提出來了。Othree 這篇文章有蠻清楚的介紹。不過當時提出來的草稿經過翻修、並且併入 HTML 規格之後,現在已經簡化到剩下兩種用法:以裝置像素密度 (device pixel ratio) 為基準、或是以 Viewport 為基準。

以裝置像素密度為基準

這個最常用到的情況,就是要為了 Retina 螢幕或是其他類似的 HiDPI 螢幕提供不同尺寸的圖片,以確保圖片在螢幕上看起來夠清晰。以 Retina 螢幕來說,就必須提供長寬都是 2x 的圖片;如果目標是 iPad Air 2 的話,可能需要提供到 3x。

用法相當簡單:

<img src="source.jpg" srcset="source_2x.jpg 2x, source_3x.jpg 3x">

這樣在 Retina 螢幕下,支援的瀏覽器就會自動去抓 source_2x.jpg 來用,不會再去找 source.jpg 了。

以 Viewport 為基準

隨著 Responsive Web Design 成為主流,一張圖片可能會隨著視窗寬度縮成不同大小。這時候就很適合配合圖片實際需要的大小,指定不同尺寸的原始檔;讓小螢幕可以給他比較小的圖片、大螢幕再下載大一點的圖片,減少行動裝置上不必要的資源浪費。

寬度的指定方法是 300w,意思是「圖片在網頁上最寬到 300 以內」的情況。不過這裡要考慮的是,指定的「寬度」是指圖片在螢幕上實際會被畫出來的「實際像素寬度」。假設你在 Retina 螢幕上,有一張圖片指定他為 300px 寬,那麼這張圖片實際的 Viewport 就會是 300 × 2 = 600,所以會是 600w

用法是:

<img src="source.jpg" width="100%"
     srcset="source_400.jpg 400w, source_600.jpg 600w, source_1280.jpg 1280w">

這樣在一般的 1x 螢幕上,如果把瀏覽器視窗拉到 580px 寬,就會使用 source_600.jpg。相對的,如果你是用 Retina 螢幕在瀏覽,就會挑到 source_1280.jpg 這張圖片(因為 580 × 2 = 1160)。

在早期的提案中,有 srcset="source_600.jpg 300w 2x" 的用法,在目前的標準中就直接用 srcset="source_600.jpg 600w" 取代了,讓考慮的情況比較單純。

為圖片指定大小

值得注意的是,如果你放了一張使用 srcset 來指定不同版本圖片的 <img> 卻沒有為其指定大小的話,預設的寬度會變成 100vw──也就是 Viewport 的 100%,通常等於瀏覽器的畫面寬度。所以要記得幫這個 <img> 指定他的寬度,或是可以用一樣併入 HTML 規格的 sizes 屬性來做更彈性的大小調整。

更新: 如果你使用了 srcset 搭配 w 表示法來為圖片提供多種尺寸的版本時,根據目前的 HTML 標準,你必須同時使用 sizes 屬性來描述這張圖片在不同情況下會有多大。也只有在你正確的提供了 sizes 屬性時,瀏覽器才有辦法更有效的去決定要載入哪張圖片版本來使用。

sizes 屬性可以搭配 Media Query 來使用,以上面的例子來改的話會變成:

<img src="source.jpg"
     sizes="(max-width: 400px) 80vw, 50vw"
     srcset="source_400.jpg 400w, source_600.jpg 600w, source_1280.jpg 1280w">

意思是「如果 viewport 最寬在 400px 以內的話,寬度為 viewport 的 80%;否則為 viewport 的 50%」。

srcset 使用的限制

我們在使用 srcset 的時候,2x300w 這兩種表示法是無法混用的。如果一個 <img> 裡面用了 300w 這種表示法,那張圖片的 srcset 就必須統一都用這種 w 表示法。下面這種用法就會是錯誤的:

<!-- Wrong example, do not copy! -->
<img src="wrong_example.jpg" width="100%"
     srcset="source_600.jpg 600w, source_1280.jpg 2x">

另外一旦你在 <img> 上面使用了 sizes 屬性來指定彈性大小,那麼在 srcset 裡面就只能用寬度為基準的 w 表示法。最後是使用 w 表示法時,你寫的寬度要符合對應的圖片的真正寬度。以上面的例子來說,source_1280.jpg 1280w 表示那張 source_1280.jpg 就真的要有 1280px 那麼寬才行。

瀏覽器支援

瀏覽器支援度是比較可惜的地方,根據 Can I Use 上面的資料顯示,目前只有 Chrome 跟(核心是 Chromium 的)Opera 有完整支援;以 Webkit 為核心的 Safari 及 iOS Safari 目前只支援 x 表示法。Firefox 則是從 32 版就實作了,但是目前藏在隱藏設定裡面,尚未正式開放。IE 則是「開發中」。

srcset 在各家瀏覽器的支援表

[Update 1/4]: 實測發現 Webkit nightly build 支援完整的 srcset,只是不知道 Apple 什麼時候才要放進去 Safari release 裡面。

所以現階段來說,srcset 還沒有辦法直接投入大量使用;不過如果是想要處理 Retina 圖片的問題,我覺得現在就可以用了,畢竟對於 Retina 螢幕使用者來說,有蠻高機率會用到支援 srcsetx 表示法的瀏覽器。另外如果想要加強圖片在不同大小的下載行為,我覺得現在也可以開始用了,最多就是 fallback 回去單一的 src 而已。

comments powered by Disqus