在 HTML 中使用響應式影像

在本文中,我們將學習響應式影像的概念——在具有各種螢幕尺寸、解析度和其他此類功能的裝置上都能很好地工作的影像——並瞭解 HTML 提供了哪些工具來幫助實現它們。這有助於提高不同裝置上的效能。

為什麼需要響應式影像?

讓我們檢查一個典型的場景。一個典型的網站可能包含一個頁首影像和頁首下方的一些內容影像。頁首影像可能會橫跨頁首的整個寬度,而內容影像將適合內容列中的某個位置。這是一個例子

Our example site as viewed on a wide screen - here the first image works OK, as it is big enough to see the detail in the center.

這在寬屏裝置(例如筆記型電腦或桌上型電腦)上執行良好(您可以線上檢視示例,並在 GitHub 上找到原始碼)。在本課程中我們不會過多討論 CSS,除了說

  • 主體內容已設定為最大寬度 1200 畫素——在超過該寬度的視口中,主體保持 1200 畫素並自行在可用空間中居中。在小於該寬度的視口中,主體將保持視口寬度的 100%。
  • 頁首影像已設定,因此其中心始終保持在頁首的中心,無論頁首設定為多寬。如果網站在較窄的螢幕上檢視,影像中心的重要細節(人物)仍然可見,而多餘的部分則丟失在兩側。它的高度為 200 畫素。
  • 內容影像已設定,如果主體元素變得小於影像,影像將開始縮小,以便它們始終保持在主體內部,而不是溢位。

然而,當您開始在窄屏裝置上檢視網站時,就會出現問題。下面的頁首看起來還不錯,但對於移動裝置來說,它開始佔據了大量的螢幕高度。而且在這個尺寸下,很難看清第一個內容影像中的兩個人的面孔。

Our example site as viewed on a narrow screen; the first image has shrunk to the point where it is hard to make out the detail on it.

一種改進方法是,當在窄屏上檢視網站時,顯示影像的裁剪版本,該版本顯示影像的重要細節。對於平板電腦等中等寬度螢幕裝置,可以顯示第二個裁剪影像。這種針對各種佈局提供不同裁剪影像的普遍問題通常被稱為藝術指導問題

此外,如果是在移動螢幕上檢視,則無需在頁面中嵌入如此大的影像。這樣做會浪費頻寬;特別是,移動使用者不希望透過下載為桌面使用者準備的大影像來浪費頻寬,因為一個小影像就足以滿足他們的裝置需求。相反,當小型光柵影像顯示大於其原始尺寸時,它會開始顯得顆粒狀(光柵影像是固定數量的畫素寬度和固定數量的畫素高度)。理想情況下,應該向使用者的網路瀏覽器提供多種解析度。然後瀏覽器可以根據使用者裝置的螢幕尺寸確定要載入的最佳解析度。這被稱為解析度切換問題

更復雜的是,有些裝置具有高解析度螢幕,需要比您預期更大的影像才能很好地顯示。

您可能認為向量影像可以解決這些問題,它們在一定程度上確實可以——它們檔案大小小,縮放效果好,您應該儘可能使用它們。但是,它們不適用於所有影像型別。向量影像非常適合簡單的圖形、圖案、介面元素等,但要建立具有您在照片中看到的那種細節的向量影像會變得非常複雜。JPEG 等柵格影像格式更適合我們上面示例中看到的影像型別。

這種問題在 90 年代初中期網際網路剛出現時並不存在——那時唯一存在的瀏覽網路的裝置是桌上型電腦和筆記型電腦,所以瀏覽器工程師和規範編寫者甚至沒有考慮實現解決方案。響應式影像技術最近才被實施,透過讓您向瀏覽器提供多個影像檔案來解決上述問題,這些檔案要麼都顯示相同的內容但包含不同數量的畫素(解析度切換),要麼是適合不同空間分配的不同影像(藝術指導)。

注意:本文討論的新功能——srcset/sizes/<picture>——都支援現代桌面和移動瀏覽器。

如何建立響應式影像?

在本節中,我們將介紹上面說明的兩個問題,並展示如何使用 HTML 的響應式影像功能來解決它們。您應該注意,本節我們將重點關注<img>元素,如上面示例的內容區域所示——網站標題中的影像僅用於裝飾,因此使用 CSS 背景影像實現。CSS 可以說比 HTML 擁有更好的響應式設計工具,我們將在未來的 CSS 模組中討論這些。

解析度切換:不同尺寸

那麼,我們希望透過解析度切換解決什麼問題?我們希望顯示相同的影像內容,只是根據裝置的大小或小——這就是我們示例中第二個內容影像的情況。傳統的標準<img>元素只允許您將瀏覽器指向單個原始檔

html
<img src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy" />

但是,我們可以使用兩個屬性——srcsetsizes——來提供幾個額外的源影像以及幫助瀏覽器選擇正確影像的提示。您可以在 GitHub 上的responsive.html示例中看到一個例子(另請參見原始碼

html
<img
  srcset="elva-fairy-480w.jpg 480w, elva-fairy-800w.jpg 800w"
  sizes="(width <= 600px) 480px,
         800px"
  src="elva-fairy-800w.jpg"
  alt="Elva dressed as a fairy" />

srcsetsizes 屬性看起來很複雜,但如果像上面那樣格式化它們,將屬性值的不同部分放在不同的行上,它們就不難理解了。每個值都包含一個逗號分隔的列表,這些列表的每個部分都由三個子部分組成。現在讓我們來逐一介紹每個內容

srcset 定義了我們允許瀏覽器選擇的影像集,以及每個影像的大小。每組影像資訊之間用逗號分隔。對於每一組,我們寫

  1. 一個影像檔名 (elva-fairy-480w.jpg)
  2. 一個空格
  3. 影像的固有畫素寬度480w)——請注意,這裡使用的是 w 單位,而不是您可能預期的 px。影像的固有大小是其真實大小,可以透過檢查計算機上的影像檔案來找到(例如,在 Mac 上,您可以在 Finder 中選擇影像並按 Cmd + I 以調出資訊螢幕)。

sizes 定義了一組媒體條件(例如,螢幕寬度),並指明瞭當某些媒體條件為真時,最適合選擇的影像大小——這些就是我們之前談到的提示。在這種情況下,在每個逗號之前我們寫

  1. 一個媒體條件(width <= 600px))——您將在CSS 主題中瞭解更多關於這些條件的資訊,但現在我們只說媒體條件描述了螢幕可能處於的一種狀態。在這種情況下,我們說的是“當視口寬度為 600 畫素或更小時”。
  2. 一個空格
  3. 當媒體條件為真時,影像將填充的槽位寬度 (480px)

注意:sizes 中,您可以使用任何長度值。例如,您可以提供一個相對於視口的寬度(例如,50vw),而不是提供一個絕對寬度(例如,480px)。但是,您不能使用百分比作為槽位寬度。您可能已經注意到,最後一個槽位寬度沒有媒體條件(當所有媒體條件都不為真時,會選擇此預設值)。瀏覽器會忽略第一個匹配條件之後的所有內容,因此請注意媒體條件的順序。

因此,有了這些屬性,瀏覽器將

  1. 檢視螢幕尺寸、畫素密度、縮放級別、螢幕方向和網路速度。
  2. 找出 sizes 列表中第一個為真的媒體條件。
  3. 檢視該媒體查詢給定的槽位大小。
  4. 載入 srcset 列表中引用的大小與槽位大小相同的影像。如果顯示大小沒有精確匹配,瀏覽器將選擇第一個大於所選槽位大小的影像並將其縮小以適應。

就是這樣!此時,如果支援的瀏覽器以 480px 的視口寬度載入頁面,則 (width <= 600px) 媒體條件將為真,因此瀏覽器會選擇 480px 槽位。elva-fairy-480w.jpg 將被載入,因為其固有寬度 (480w) 最接近槽位大小。800px 的圖片在磁碟上是 128KB,而 480px 的版本只有 63KB——節省了 65KB。現在,想象一下如果這是一個有很多圖片的頁面。使用這種技術可以為移動使用者節省大量頻寬。

注意:在使用桌面瀏覽器測試時,如果您將視窗設定為最窄寬度時瀏覽器無法載入較窄的影像,請檢視視口是什麼(您可以透過進入瀏覽器的 JavaScript 控制檯並輸入 document.querySelector('html').clientWidth 來估算)。不同的瀏覽器有它們允許您減小視窗寬度的最小尺寸,並且它們可能比您想象的要寬。在使用移動瀏覽器測試時,您可以使用 Firefox 的 about:debugging 頁面等工具,使用桌面開發者工具檢查載入在移動裝置上的頁面。

要檢視載入了哪些影像,您可以使用 Firefox DevTools 的網路監視器選項卡或 Chrome DevTools 的網路面板。對於 Chrome,您可能還需要停用快取以防止它選擇已經下載的影像。

不支援這些功能的舊版瀏覽器將直接忽略它們。相反,這些瀏覽器將照常載入 src 屬性中引用的影像。

注意:在上面連結的示例的<head>中,您會找到<meta name="viewport" content="width=device-width">這一行:這會強制移動瀏覽器採用其真實的視口寬度來載入網頁(一些移動瀏覽器會謊報其視口寬度,而是以更大的視口寬度載入頁面,然後縮小載入的頁面,這對於響應式圖片或設計來說作用不大)。

解析度切換:相同大小,不同解析度

假設您有一張影像,它將在具有不同螢幕解析度的顯示器上以相同的真實世界尺寸渲染。透過提供更高解析度的影像版本,您可以在高解析度顯示器上提供更好的使用者體驗。

為此,您可以透過使用帶有 x 描述符且不帶 sizessrcset 來讓瀏覽器選擇合適解析度的影像——語法更簡單!您可以在 srcset-resolutions.html 中找到一個示例(另請參見原始碼

html
<img
  srcset="elva-fairy-320w.jpg, elva-fairy-480w.jpg 1.5x, elva-fairy-640w.jpg 2x"
  src="elva-fairy-640w.jpg"
  alt="Elva dressed as a fairy" />

請注意,即使影像始終以相同尺寸顯示,在高解析度顯示器上您也能看到更多細節。

A picture of a little girl dressed up as a fairy, with an old camera film effect applied to the image

在此示例中,以下 CSS 應用於影像,使其在螢幕上(也稱為 CSS 畫素)的寬度為 320 畫素

css
img {
  width: 320px;
}

在這種情況下,不需要 sizes——瀏覽器會根據正在顯示的顯示器的解析度來決定,並提供 srcset 中引用的最合適的影像。因此,如果訪問頁面的裝置是標準/低解析度顯示器,每個 CSS 畫素代表一個裝置畫素,則會載入 elva-fairy-320w.jpg 影像(隱含 1x,因此您無需包含它)。如果裝置具有每 CSS 畫素兩個或更多裝置畫素的高解析度,則會載入 elva-fairy-640w.jpg 影像。640px 影像為 93KB,而 320px 影像僅為 39KB。

藝術指導

回顧一下,藝術指導問題是指為了適應不同的影像顯示尺寸而希望更改顯示的影像。例如,當在桌面瀏覽器上檢視時,網頁包含一張帶有中間人物的大型風景照片。當在移動瀏覽器上檢視時,同一張影像會被縮小,使得影像中的人物變得非常小且難以看清。最好在移動裝置上顯示一張較小的肖像影像,該影像會放大人物。 <picture> 元素允許我們實現這種解決方案。

回到我們最初的not-responsive.html示例,我們有一個急需藝術指導的影像

html
<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />

讓我們用<picture>來解決這個問題!像<video><audio>一樣,<picture>元素是一個包裝器,包含幾個<source>元素,它們為瀏覽器提供了不同的來源供選擇,然後是至關重要的<img>元素。responsive.html中的程式碼如下

html
<picture>
  <source media="(width < 800px)" srcset="elva-480w-close-portrait.jpg" />
  <source media="(width >= 800px)" srcset="elva-800w.jpg" />
  <img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva" />
</picture>
  • <source>元素包含一個帶有媒體條件的media屬性——就像第一個srcset示例一樣,這些條件是決定顯示哪個影像的測試——第一個返回true的影像將被顯示。在這種情況下,如果視口寬度小於800畫素,則顯示第一個<source>元素的影像。如果視口寬度為800畫素或更大,則顯示第二個。
  • srcset 屬性包含要顯示的影像路徑。正如我們上面看到的 <img><source> 可以帶一個引用多個影像的 srcset 屬性,以及一個 sizes 屬性。因此,您可以透過 <picture> 元素提供多個影像,但也可以為每個影像提供多個解析度。實際上,您可能不會經常這樣做。
  • 在所有情況下,您都必須在 </picture> 之前提供一個帶有 srcalt<img> 元素,否則不會顯示任何影像。這提供了一個預設情況,適用於所有媒體條件都不為真時(實際上您可以刪除此示例中的第二個 <source> 元素),以及一個不支援 <picture> 元素的瀏覽器的回退。

此程式碼允許我們在寬屏和窄屏顯示器上顯示合適的影像,如下所示

Our example site as viewed on a wide screen - here the first image works OK, as it is big enough to see the detail in the center.Our example site as viewed on a narrow screen with the picture element used to switch the first image to a portrait close up of the detail, making it a lot more useful on a narrow screen

注意:您應該只在藝術指導場景中使用 media 屬性;當您使用 media 時,不要在 sizes 屬性中也提供媒體條件。

為什麼我們不能只用 CSS 或 JavaScript 來實現呢?

當瀏覽器開始載入頁面時,它會在主解析器開始載入和解釋頁面的 CSS 和 JavaScript 之前開始下載(預載入)任何影像。這種機制通常有助於減少頁面載入時間,但對於響應式影像來說卻無濟於事——因此需要實現 srcset 等解決方案。例如,您無法載入<img>元素,然後用 JavaScript 檢測視口寬度,如果需要的話再動態將源影像更改為較小的影像。到那時,原始影像已經載入完畢,您還會載入小影像,這在響應式影像方面甚至更糟。

實現您自己的響應式影像

在此練習中,我們希望您勇敢地獨自完成,大部分。我們希望您使用 <picture> 實現自己的適合藝術指導的窄屏/寬屏截圖,並使用 srcset 實現一個解析度切換示例。

  1. 編寫一些 HTML 來包含您的程式碼(如果您喜歡,可以使用 not-responsive.html 作為起點)。
  2. 找到一張漂亮的寬屏風景圖片,其中包含一些細節。使用圖形編輯器建立其網路尺寸版本,然後將其裁剪以顯示放大細節的較小部分,並建立第二張圖片(大約 480 畫素寬比較合適)。
  3. 使用 <picture> 元素實現藝術指導圖片切換器!
  4. 建立不同尺寸的多個影像檔案,每個檔案顯示相同的圖片。
  5. 使用 srcset/sizes 建立一個解析度切換示例,無論是根據裝置解析度以不同解析度提供相同尺寸的影像,還是根據視口寬度提供不同尺寸的影像。

總結

響應式影像的講解到此結束——我們希望您喜歡嘗試這些新技術。回顧一下,我們在這裡討論了兩個截然不同的問題

  • 藝術指導:指您希望為不同佈局提供裁剪影像的問題——例如,為桌面佈局顯示一張顯示完整場景的橫向影像,為移動佈局顯示一張放大主要物件的縱向影像。您可以使用<picture>元素解決此問題。
  • 解析度切換:指您希望為窄屏裝置提供較小的影像檔案,因為它們不需要像桌面顯示器那樣巨大的影像——以及為高密度/低密度螢幕提供不同解析度的影像。您可以使用向量圖形(SVG 影像)和帶有sizes屬性的srcset來解決此問題。

另見