一次搞懂響應式圖片(Responsive Images)如何使用
大家或許有聽過響應式設計(Responsive Web Design),也就是依照不同螢幕尺寸去設計不同樣式的畫面,已達到更好的使用者體驗,而響應式圖片也是類似的道理,這篇文章會介紹為什麼需要響應式圖片,和如何使用,一起看下去吧!
為什麼需要使用響應式圖片
我們可以想一下,如果在所有螢幕尺寸都使用同一張圖片會有什麼問題呢?如果解析度太低,在畫質好的螢幕上看起來會像馬賽克;但如果解析度太高,在網路速度慢的狀況又要等很久才能看到完整的圖片、而且在螢幕尺寸較小的行動裝置顯示高解析度圖片也顯得浪費。無論是哪種情況,都會大大地影響使用者體驗,而這時候響應式圖片正好可以解決這個問題。
很幸運地,HTML 已經內建了幾種可以使用響應式圖片的方式,我們就一個一個看如何使用吧!
img
+ srcset & sizes 屬性
使用 <img>
時如果只有使用 src
屬性,那無論在任何螢幕尺寸都會下載指定的圖片。但透過 srcset
,我們就可以指定在什麼螢幕尺寸要顯示什麼大小的圖片,例如:
<img
src="https://placehold.co/600x400/png"
alt="placeholder"
srcset="
https://placehold.co/300x200/png 300w,
https://placehold.co/600x400/png 600w,
https://placehold.co/900x600/png 900w
"
/>
上面的範例中我們用 srcset
指定了對應的圖片:
- 在螢幕尺寸小於 300w 時,顯示 300x200 這張圖片
- 在螢幕尺寸大於 300w 但小於 600w 時,顯示 600x400 這張圖片
- 在螢幕尺寸大於 600w 時,顯示 900x600 這張圖片
你可能有注意到,這裡使用的是 w
而不是常見的 px
,這是因為在畫素較好的螢幕(例如:4K 解析度)上,同一個 px 可能會對應到 2 個 CSS px,而 w
代表的是真實的圖片大小(intrinsic size)。
我們可以透過
window.devicePixelRatio
查看目前的像素比例(DPR);如果想要查看不同 DPR 下的顯示的話可以透過瀏覽器 devtools 的 RWD 模式更改
圖片寬度固定,但維持一樣的解析度
如果圖片不論在什麼畫面的寬都固定是 100px,如果都使用同一張圖片的話,在高解析度螢幕上可能會顯得模糊,這時候可以透過將 w
更換成 1x
、 2x
的方式達成
<img
src="https://placehold.co/600x400/png"
alt="placeholder"
srcset="
https://placehold.co/300x200/png, /* 不需要指定 1x 因為是預設值 */
https://placehold.co/600x400/png 1.5x,
https://placehold.co/900x600/png 2x
"
/>
如果圖片寬度不是 100vw 怎麼辦?
上面的範例是以 100% 瀏覽器寬作為基準,但如果圖片在網頁上顯示的大小只有畫面的一半呢?如果只有用 srcset
的話那會以瀏覽器寬作為基準,但這不是我們想要的結果。此時 sizes
屬性就派上用場了!
我們可以透過 sizes
指定當前的圖片寬度,例如:
<img
src="https://placehold.co/600x400/png"
alt="placeholder"
srcset="
https://placehold.co/300x200/png 300w,
https://placehold.co/600x400/png 600w,
https://placehold.co/900x600/png 900w,
https://placehold.co/1200x800/png 1200w,
https://placehold.co/1500x1000/png 1500w,
"
sizes="media(max-width: 800px) 100vw, 800px"
style="max-width: 800px"
/>
新增的 sizes
可以看到有兩個部分:
media(max-width: 800px) 100vw
:當螢幕寬小於 800px 的時候,用完整的螢幕寬當作基準800px
:預設的圖片寬度。當不符合前一條件時,會以 800px 當作圖片的寬。可以看到在srcset
也新增了 1200w 和 1500w 的圖片,即便當圖片寬已經限制在 800px,瀏覽器仍會依照 DPR 去選擇適合的圖片
使用 <img>
搭配 srcset
和 sizes
就可以做到響應式圖片的效果了,但也有幾個需要注意的點:
sizes
的順序由前到後執行,如果前面就符合條件,那後面的條件就不會被執行到了,所以要確保寫得條件(media query)順序正確
例如
media(max-width: 700px) 80vw, media(max-width: 500px) 100vw, 800px
sizes
裡的單位只能用vw
和px
而不能用%
,這是因為瀏覽器不知道圖片在畫面中佔的比例,如果要計算的話還需要等頁面載入才能知道在畫面上的位置和比例,這樣做反而不切實際。
除了上面提到需要注意的點,如果我們想用新一點的圖片格式呢?例如 WebP 或 AVIF 呢?或是在大螢幕或小螢幕分別顯示完全不同的圖片呢?這時候就可以選擇 <picture>
了。
picture
元素
用法如下方範例:
<picture>
<source srcset="wide.png" media="(min-width: 768px)" />
<source srcset="mid.png" media="(min-width: 1024px)" />
<img src="narrow.png" alt="example" />
</picture>
可以看到用了新的元素 <picture>
,並使用 <source>
指定在不同條件(media
)下要顯示的圖片(srcset
),最後再放上 <img>
作為 fallback 的圖片。
srcset
:可以放上圖片來源或是跟<img>
的屬性一樣加上尺寸(例如:
https://placehold.co/300x200/png 300w
)media
:要使用此 source 的條件
要注意的是 picture 來源執行順序會由上往下,也就是說如果把 <img>
放到第一位,那下面的 <source>
也都會被跳過了。
使用不同格式的圖片
<picture>
除了響應式圖片還可以用來放不同格式的圖片,讓我們可以依照瀏覽器支援程度使用最新的圖片格式,在一樣的畫質下檔案大小卻更小。需要在 source 裡使用 type
屬性指定圖片格式:
<picture>
<source srcset="photo.avif" type="image/avif" />
<source srcset="photo.webp" type="image/webp" />
<img src="photo.jpg" alt="photo" />
</picture>
以上方範例來說,如果瀏覽器不支援 image/avif
的話,會跳過該 <source>
直到找到符合條件的,如果都不支援的話,就會使用 fallback 的 <img>
。
上面 <picture>
的使用可以在下方 Stackblitz 試玩看看!
https://stackblitz.com/edit/js-oumms7?embed=1&file=index.html
值得注意的是,使用 <picture>
時會在螢幕大小改變時下載適合的圖片顯示;sizes
類似,但只有在螢幕大小變大時會下載對應的圖片,如果在縮小螢幕的狀況下不會再顯示小螢幕的圖片,這樣的好處是網路使用又更少了,但易用性卻變差了。
該使用哪一種呢?
就我而言,我會覺得 <picture>
比較好用,因為語法較易懂,使用上也比較直覺,指定什麼尺寸就會出現什麼圖片,而且可以依照 mobile/desktop 設計各自適合的圖片顯示。