Like Share Discussion Bookmark Smile

J.J. Huang   2019-05-23   Web   瀏覽次數:

Web - 第十四章 | HTML 響應式圖片

在開始之前我必須要說,這篇對我來說太重要了,因為目前工作上在全面的調整公司網站的網頁,改為響應式網頁設計(英語:Responsive web design,通常縮寫為RWD),然後這篇準備要看的是「響應式圖片」,正好可以補充一下一些技術知識上的不足。

響應式網頁設計(英語:Responsive web design,通常縮寫為RWD),或稱自適應網頁設計、回應式網頁設計、對應式網頁設計。 是一種網頁設計的技術做法,該設計可使網站在不同的裝置(從桌面電腦顯示器到行動電話或其他行動產品裝置)上瀏覽時對應不同解析度皆有適合的呈現,減少使用者進行縮放、平移和捲動等操作行為。

對於網站設計師和前端工程師來說,有別於過去需要針對各種裝置進行不同的設計,使用此種設計方式將更易於維護網頁。

為什麼要用響應式圖片?

一種可以在不同的屏幕尺寸和分辨率的設備上都能良好工作以及其他特性的圖片,響應式圖片僅僅只是響應式web設計的一部分。

範例網站

這適用於寬屏幕設備,例如筆記本電腦或台式機。

  • 主體內容已設置為最大寬度為1200像素 - 在高於該寬度的視口中,主體保持在1200像素並且在可用空間中居中。在寬度以下的視口中,主體將保持視口寬度的100%。
  • 標題圖片已設置為無論標題設置的寬度多少,其中心始終位於標題的中心。如果在較窄的屏幕上觀看該網站,仍然可以看到圖片中心的重要細節(人物),而兩邊超出的部分都消失了。它的高度是200px。
  • 已經設置了內容圖片,使得如果主體元素變得小於圖片,則圖片開始收縮,使得它們總是保持在體內,而不是溢出它。

但是,當你開始在窄屏幕設備上查看網站時會出現問題。下面的標題看起來不錯,但它開始佔用移動設備的很多屏幕高度。在這個尺寸下,很難在第一個內容圖片中看到人。

一個改進的方法是,當網站在狹窄的屏幕上觀看時,顯示一幅圖片的包含了重要細節的裁剪版本,第二個被裁剪的圖片會在像平板電腦這樣的中等寬度的屏幕設備上顯示,這就是眾所周知的藝術方向問題(art direction problem)

另外,如果是在小屏手機屏幕上顯示網頁,那麼沒有必要在網頁上嵌入這樣大的圖片。這被稱之為分辨率切換問題(resolution switching problem)。點陣圖有固定數量的像素寬,固定數量的像素高,與 向量圖 外觀相同,但本質不同。如果顯示尺寸大於原始尺寸,一張自身較小的點陣圖看起來會有顆粒感(向量圖則不會)。

相反,沒有必要在比圖片實際尺寸小的屏幕上顯示一張大圖,這樣做會浪費帶寬——當可以在設備上使用小圖片時,手機用戶尤其不願意因為下載用於桌面的大圖片而浪費帶寬。理想的情況是當訪問網站時依靠不同的設備來提供不同的分辨率圖片和不同尺寸的圖片。

讓事情變得複雜的是,有些設備有很高的分辨率,為了顯示的更出色,可能需要超出你預料的更大的圖片。這從本質上是一樣的問題,但在環境上有一些不同。

你可能會認為向量圖形能解決這些問題,在某種程度上是這樣的——它們無論是文件大小還是比例都合適,無論在哪裡你都應該盡可能的使用它們。然而,它們並不適合所有的圖片類型,雖然在簡單圖形、圖案、界面元素等方面較好,但如果是有大量的細節的照片,建立向量圖片會變得非常複雜。像JPEG格式這樣的點陣圖會更適合上面例子中的圖片。

當web第一次出現時,這樣的問題並不存在,在上世紀90年代中期,僅僅可以通過筆記本電腦和台式機來瀏覽web頁面,所以瀏覽器開發者和規範制定者甚至沒有想到要實現這種解決方式(響應式開發)。最近應用的響應式圖片技術,通過讓瀏覽器提供多個圖片文件來解決上述問題,比如使用相同顯示效果的圖片但包含多個不同的分辨率(分辨率切換),或者使用不同的圖片以適應不同的空間分配(藝術方向)。


怎樣建立響應式圖片?

專注於HTML的<img>,但網站圖片僅是裝飾性的,實際上應該要用CSS的背景圖片來實現。CSS是比HTML更好的響應式設計的工具。

分辨率切換:不同尺寸的

<img>傳統上,標準元素只允許你將瀏覽器指向單個源文件:

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

這邊可以使用兩個新屬性 - srcset和sizes- 提供幾個額外的源圖片以及提示,以幫助瀏覽器選擇正確的。

1
2
3
4
5
6
7
<img srcset="elva-fairy-320w.jpg 320w,
elva-fairy-480w.jpg 480w,
elva-fairy-800w.jpg 800w"
sizes="(max-width: 320px) 280px,
(max-width: 480px) 440px,
800px"
src="elva-fairy-800w.jpg" alt="Elva dressed as a fairy">

srcset和sizes屬性看起來很複雜,但是如果你按照上圖所示進行格式化,那麼他們並不是很難理解,每一行有不同的屬性值。每個值都包含逗號分隔的列表。列表的每一部分由三個子部分組成。

srcset定義了我們允許瀏覽器選擇的圖片集,以及每個圖片的大小。在每個逗號之前,我們寫:

  • 一個文件名 ( elva-fairy-480w.jpg.)
  • 一個空格
  • 圖片的固有寬度(以像素為單位)(480w)——注意到這裡使用w單位,而不是你預計的px。這是圖片的真實大小,可以通過檢查你電腦上的圖片文件找到(例如,在Mac上,你可以在Finder上選擇這個圖片,然後按Cmd+ I 來顯示訊息)。

sizes定義了一組媒體條件(例如屏幕寬度)並且指明當某些媒體條件為真時,什麼樣的圖片尺寸是最佳選擇—我們在之前已經討論了一些提示。在這種情況下,在每個逗號之前,我們寫:

  • 一個媒體條件((max-width:480px))——你會在CSS topic中學到更多的。但是現在我們僅僅討論的是媒體條件描述了屏幕可能處於的狀態。在這裡,我們說“當視窗的寬度是480像素或更少”。
  • 一個空格
  • 當媒體條件為真時,圖片將填充的槽的寬度(440px)

注意:對於插槽寬度,你可以提供固定值(px,em)或長度(vw),但不提供百分比。你可能已經註意到最後一個插槽寬度沒有介質條件(這是在沒有任何介質條件為真時選擇的默認值)。瀏覽器在第一個匹配條件後忽略所有內容,因此請注意條件的順序。

所以,有了這些屬性,瀏覽器會:

  • 查看設備寬度
  • 檢查sizes列表中哪個媒體條件是第一個為真
  • 查看給予該媒體查詢的槽大小
  • 加載srcset列表中引用的最接近所選的槽大小的圖片

就是這樣!所以在這裡,如果支持瀏覽器以視窗寬度為480px來加載頁面,那麼(max-width: 480px)的媒體條件為真,因此440px的槽會被選擇,所以elva-fairy-480w.jpg將加載,因為它的的固定寬度(480w)最接近於440px。800px的照片大小為128KB而480px版本僅有63KB大小—節省了65KB。現在想像一下,如果這是一個有很多圖片的頁面。使用這種技術會節省移動端用戶的大量帶寬。

注意:老舊的瀏覽器不支持這些特性,它會忽略這些特徵。並繼續正常加載src屬性引用的圖片文件。

注意 :在HTML文件中的<head>標籤裡,你將會找到這一行代碼 <meta name=”viewport” content=”width=device-width”>:這行代碼會強制地讓手機瀏覽器採用它們真實視圖的寬度來加載網頁(有些手機瀏覽器會提供不真實的視圖寬度,然後加載比瀏覽器真實視圖的寬度大的寬度的網頁,然後再縮小加載的頁面,這樣的做法對響應式圖片或其他設計,沒有任何幫助。我們會在未來的模組教給你更多關於這方面的知識)。

開發者工具

這邊提供Chrome開發者工具的使用教學網站,這邊提供非常完善的功能介紹和使用方式。

Chrome 開發者工具

分辨率切換:相同尺寸,不同的分辨率

如果你支持多種分辨率顯示,但希望每個人在屏幕上看到的圖片的實際尺寸是相同的,你可以讓瀏覽器通過srcset和x語法結合——一種更簡單的語法——而不用sizes,來選擇適當分辨率的圖片。

1
2
3
4
<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">
1
2
3
img {
width: 320px;
}

在這種情況下,sizes不需要 - 瀏覽器只需計算出顯示的顯示分辨率,並提供最合適的圖片srcset。因此,如果訪問頁面的設備具有標準/低分辨率顯示器,其中一個設備像素代表每個CSS像素,elva-fairy-320w.jpg則將加載圖片(暗示1x,因此你不需要包含它。)如果設備具有每個CSS像素或更高的兩個設備像素的高分辨率,elva-fairy-640w.jpg將加載圖片。640px圖片為93KB,而320px圖片僅為39KB。

注:以上「分辨率切換:相同尺寸,不同的分辨率」我沒有試驗成功,也沒有完全理解。這邊僅作筆記記錄。我需要再針對這個研究一下。

藝術指導

藝術方向問題涉及要更改顯示的圖片以適應不同的圖片顯示尺寸。例如,如果在桌面瀏覽器上的一個網站上顯示一張大的、橫向的照片,照片中央有個人,然後當在移動端瀏覽器上瀏覽這個網站時,照片會縮小,這時照片上的人會變得非常小,看起來會很糟糕。這種情況可能在移動端顯示一個更小的肖像圖會更好,這樣人物的大小看起來更合適。<picture>元素允許我們這樣實現。

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

改用<picture>!就像<video>和<audio>,<picture>素包含了一些<source>元素,它使瀏覽器在不同資源間做出選擇,緊跟著的是最重要的<img>元素。

1
2
3
4
5
<picture>
<source media="(max-width: 799px)" srcset="elva-480w-close-portrait.jpg">
<source media="(min-width: 800px)" srcset="elva-800w.jpg">
<img src="elva-800w.jpg" alt="Chris standing up holding his daughter Elva">
</picture>
  • <source>元素包含一個media屬性,這一屬性包含一個媒體條件——就像第一個srcset例子,這些條件來決定哪張圖片會顯示——第一個條件返回真,那麼就會顯示這張圖片。在這種情況下,如果視窗的寬度為799px或更少,第一個<source>元素的圖片就會顯示。如果視窗的寬度是800px或更大,就顯示第二張圖片。
  • srcset屬性包含要顯示圖片的路徑。請注意,正如我們在<img>上面看到的那樣,<source>可以使用引用多個圖片的srcset屬性,還有sizes屬性。所以你可以通過一個<picture>元素提供多個圖片,不過也可以給每個圖片提供多分辨率的圖片。實際上,你可能不想經常做這樣的事情。
  • 在任何情況下,你都必須在</picture>之前正確提供一個<img>元素以及它的src和alt屬性,否則不會有圖片顯示。當媒體條件都不返回真的時候(你可以在這個例子中刪除第二個<source>元素),它會提供圖片;如果瀏覽器不支持<picture>元素時,它可以作為後備方案。

注意 :你應該僅僅當在藝術方向場景下使用media屬性;當你使用media時,不要在sizes屬性中也提供媒體條件。

為什麼我們不能使用CSS或JavaScript來做到這一點?

當瀏覽器開始加載一個頁面,它會先下載(預加載)任意的圖片,這是發生在主解析器開始加載和解析頁面的CSS和JavaScript之前的。這是一個非常有用的技巧,平均來說,頁面加載的時間少了20%。但是,這對響應式圖片一點幫助都沒有,所以需要實現類似 srcset的方法。因為你不能先加載好<img>元素後,再用JavaScript檢測視圖的寬度,如果覺得大小不合適,就動態地加載小的圖片替換已經加載好的圖片,這樣的話,原始的圖片已經被加載了,然後你也加載了小的圖片,這樣的做法對於響應式圖片的理念來說,是很糟糕的。

大膽的使用現代圖片格式

有很多令人激動的新圖片格式(例如WebP和JPEG-2000)可以在有高質量的同時有較低的文件大小。然而,瀏覽器對其的支持參差不齊。

<picture>讓我們能繼續滿足老式瀏覽器的需要。你可以在type屬性中提供MIME類型,這樣瀏覽器就能立即拒絕其不支持的文件類型。

1
2
3
4
5
<picture>
<source type="image/svg+xml" srcset="pyramid.svg">
<source type="image/webp" srcset="pyramid.webp">
<img src="pyramid.png" alt="regular pyramid built from four equilateral triangles">
</picture>
  • 不要使用media屬性,除非你也需要藝術方向。
  • 元素中,你只可以引用在type中聲明的文件類型。
  • 像之前一樣,如果必要,你可以在srcset和sizes中使用逗號分割的列表。

小結

  • 藝術方向:當你想為不同佈局提供不同剪裁的圖片——比如在桌面佈局上顯示完整的、橫向圖片,而在手機佈局上顯示一張剪裁過的、突出重點的縱向圖片,可以用<picture>元素來實現。

  • 分辨率切換:當你想要為窄屏提供更小的圖片時,因為小屏幕不需要像桌面端顯示那麼大的圖片;以及你想為高/低分辨率屏幕提供不同分辨率的圖片時,都可以通過 vector graphics (SVG images)、 srcset以及 sizes屬性來實現。

這邊轉載了大量的文章和內容,但是每個部分我都有實際去做過,並了解過。這邊轉載主要是做筆記記錄。

註:以上參考了
MDN web docsResponsive images 文章。
維基百科回應式網頁設計 文章。