響應式影象教程

阮一峰發表於2019-06-10

網頁在不同尺寸的裝置上,都有良好的顯示效果,叫做"響應式設計"(responsive web design)。

響應式設計的網頁影象,就是"響應式影象"(responsive image)。

響應式影象的解決方案有很多,JavaScript 和 CSS 都可以實現。本文介紹最簡單的、語義性最好的 HTML 方法,瀏覽器原生支援。

一、問題的由來

我們知道,<img>標籤用於插入網頁影象,所有情況預設插入的都是同一張影象。


<img src="foo.jpg">

上面程式碼在桌面端和手機上,插入的都是影象檔案foo.jpg

這種處理方法固然簡單,但是有三大弊端。

(1)體積

一般來說,桌面端顯示的是大尺寸的影象,檔案體積較大。手機的螢幕較小,只需要小尺寸的影象,可以節省頻寬,加速網頁渲染。

(2)畫素密度

桌面顯示器一般是單倍畫素密度,而手機的螢幕往往是多倍畫素密度,即多個畫素合成為一個畫素,稱為 Retina 螢幕。影象檔案很可能在桌面端很清晰,放到手機上會有點模糊,因為畫素擴充了。

(3)視覺風格

桌面顯示器的面積較大,影象可以容納更多細節。手機的螢幕較小,許多細節是看不清的,需要突出重點。

上面兩張圖片,下方的手機圖片經過裁剪以後,更突出影象重點,明顯效果更好。

二、畫素密度的選擇:srcset屬性

為了解決上一節的這些問題,HTML 語言提供了一套完整的解決方案。首先,<img>標籤引入了srcset屬性。

srcset屬性用來指定多張影象,適應不同畫素密度的螢幕。它的值是一個逗號分隔的字串,每個部分都是一張影象的 URL,後面接一個空格,然後是畫素密度的描述符。請看下面的例子。


<img srcset="foo-320w.jpg,
             foo-480w.jpg 1.5x,
             foo-640w.jpg 2x"
     src="foo-640w.jpg">
 

上面程式碼中,srcset屬性給出了三個影象 URL,適應三種不同的畫素密度。

影象 URL 後面的畫素密度描述符,格式是畫素密度倍數 + 字母x1x表示單倍畫素密度,可以省略。瀏覽器根據當前裝置的畫素密度,選擇需要載入的影象。

如果srcset屬性都不滿足條件,那麼就載入src屬性指定的預設影象。

三、影象大小的選擇:srcset屬性 + sizes屬性

畫素密度的適配,只適合顯示區域一樣大小的影象。如果希望不同尺寸的螢幕,顯示不同大小的影象,srcset屬性就不夠用了,必須搭配sizes屬性。

第一步,srcset屬性列出所有可用的影象。


<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     src="foo-1280.jpg">

上面程式碼中,srcset屬性列出四張可用的影象,每張影象的 URL 後面是一個空格,再加上寬度描述符。

寬度描述符就是影象原始的寬度,加上字元w。上例的四種圖片的原始寬度分別為160畫素、320畫素、640畫素和1280畫素。

第二步,sizes屬性列出不同裝置的影象顯示寬度。

sizes屬性的值是一個逗號分隔的字串,除了最後一部分,前面每個部分都是一個放在括號裡面的媒體查詢表示式,後面是一個空格,再加上影象的顯示寬度。


<img srcset="foo-160.jpg 160w,
             foo-320.jpg 320w,
             foo-640.jpg 640w,
             foo-1280.jpg 1280w"
     sizes="(max-width: 440px) 100vw,
            (max-width: 900px) 33vw,
            254px"
     src="foo-1280.jpg">

上面程式碼中,sizes屬性給出了三種螢幕條件,以及對應的影象顯示寬度。寬度不超過440畫素的裝置,影象顯示寬度為100%;寬度441畫素到900畫素的裝置,影象顯示寬度為33%;寬度900畫素以上的裝置,影象顯示寬度為254px

第三步,瀏覽器根據當前裝置的寬度,從sizes屬性獲得影象的顯示寬度,然後從srcset屬性找出最接近該寬度的影象,進行載入。

假定當前裝置的螢幕寬度是480px,瀏覽器從sizes屬性查詢得到,圖片的顯示寬度是33vw(即33%),等於160pxsrcset屬性裡面,正好有寬度等於160px的圖片,於是載入foo-160.jpg

注意,sizes屬性必須與srcset屬性搭配使用。單獨使用sizes屬性是無效的。

四、<picture>標籤,<source>標籤

上面兩節分別解決了畫素密度和螢幕大小的適配,但是如果要同時適配不同畫素密度、不同大小的螢幕,應該怎麼辦呢?

這時,就要用到<picture>標籤。它是一個容器標籤,內部使用<source><img>,指定不同情況下載入的影象。


<picture>
  <source media="(max-width: 500px)" srcset="cat-vertical.jpg">
  <source media="(min-width: 501px)" srcset="cat-horizontal.jpg">
  <img src="cat.jpg" alt="cat">
</picture>

上面程式碼中,<picture>標籤內部有兩個<source>標籤和一個<img>標籤。

<source>標籤的media屬性給出媒體查詢表示式,srcset屬性就是<img>標籤的srcset屬性,給出載入的影象檔案。sizes屬性其實這裡也可以用,但由於有了media屬性,就沒有必要了。

瀏覽器按照<source>標籤出現的順序,依次判斷當前裝置是否滿足media屬性的媒體查詢表示式,如果滿足就載入srcset屬性指定的圖片檔案,並且不再執行後面的<source>標籤和<img>標籤。

<img>標籤是預設情況下載入的影象,用來滿足上面所有<source>都不匹配的情況。

上面例子中,裝置寬度如果不超過500px,就載入豎屏的影象,否則載入橫屏的影象。

下面給出一個例子,同時考慮螢幕尺寸和畫素密度的適配。


<picture>
  <source srcset="homepage-person@desktop.png,
                  homepage-person@desktop-2x.png 2x"       
          media="(min-width: 990px)">
  <source srcset="homepage-person@tablet.png,
                  homepage-person@tablet-2x.png 2x" 
          media="(min-width: 750px)">
  <img srcset="homepage-person@mobile.png,
               homepage-person@mobile-2x.png 2x" 
       alt="Shopify Merchant, Corrine Anestopoulos">
</picture>

上面程式碼中,<source>標籤的media屬性給出螢幕尺寸的適配條件,每個條件都用srcset屬性,再給出兩種畫素密度的影象 URL。

五、<source>標籤的type屬性

除了響應式影象,<picture>標籤還可以用來選擇不同格式的影象。比如,如果當前瀏覽器支援 Webp 格式,就載入這種格式的影象,否則載入 PNG 影象。


<picture>
  <source type="image/svg+xml" srcset="logo.xml">
  <source type="image/webp" srcset="logo.webp"> 
  <img src="logo.png" alt="ACME Corp">
</picture>

上面程式碼中,<source>標籤的type屬性給出影象的 MIME 型別,srcset是對應的影象 URL。

瀏覽器按照<source>標籤出現的順序,依次檢查是否支援type屬性指定的影象格式,如果支援就載入影象,並且不再檢查後面的<source>標籤了。上面例子中,影象載入優先順序依次為 svg 格式、webp 格式和 png 格式。

六、參考連結

(完)

相關文章