使用 picture 在檢視區寬度的斷點處切換正方形與寬幅圖片檔案。為每個來源設定各自的尺寸,並讓 CSS 按比例縮放選取的圖片。本指南會在 Mac 上建立並測試本機範例。
picture 如何在不同長寬比之間切換?
在 picture 內,將帶有 media 條件的 source 元素放在後備 img 之前。瀏覽器會選取第一個符合條件的來源,接著從該來源的 srcset 中選取圖片。這稱為藝術指導:針對不同版面提供不同構圖。HTML 標準明確支援這種做法。HTML 標準:圖片
三個部分會共同運作:來源選擇資源,尺寸屬性描述該資源的比例,而 CSS 控制其顯示大小。所選來源的 width 和 height 可提供內含圖片所使用的長寬比。picture 元素本身不會繪製圖片;它的 img 才會。HTML 標準:嵌入內容
請依照所需結果選擇機制:
| 需求 | 適用機制 |
|---|---|
| 在斷點處變更構圖或長寬比 | 使用 picture,搭配採用 media 的 source |
| 提供相同構圖的不同解析度 | 使用 srcset;搭配寬度描述符時使用 sizes |
| 保留單一檔案,但在固定框架內裁切 | CSS 尺寸設定與 object-fit: cover |
這些機制處理的是不同決策。藝術指導決定要顯示哪種構圖。解析度選擇讓瀏覽器在同一構圖中選擇合適的候選項目。CSS 填入方式決定所選資源如何佔據其框架。MDN 說明了 picture 的這些用途,以及它與 srcset 和填入屬性的關係。MDN:picture 元素
在 Mac 上建立完整的本機範例
此範例使用兩個原始 SVG 資源,分別包含一個橙色圓形和一個藍綠色圓角矩形。正方形版本將它們上下排列;寬幅版本則將它們並排。所有檔案都放在同一個資料夾中,切換時不需要外部資產或 JavaScript。
撰寫資源的規格很簡單:檢視區寬度小於 700px 時,使用 600 × 600 的正方形資源;寬度達 700px 以上時,使用 1200 × 600 的寬幅資源。顯示的圖片會填滿左右各留 16px 的內容區域,最大寬度為 960px。這些尺寸與斷點都是示範用的設計選擇。
儲存兩個圖形資源
建立名為 picture-demo 的資料夾。使用純文字程式碼編輯器,在資料夾中建立以下兩個檔案,並保留其確切檔名與副檔名。每個圍欄區塊都包含完整檔案;複製內容時請勿包含 Markdown 圍欄標記。
將以下內容儲存為 shapes-square.svg:
<svg xmlns="http://www.w3.org/2000/svg" width="600" height="600" viewBox="0 0 600 600">
<rect width="600" height="600" fill="#fff5df"/>
<circle cx="300" cy="180" r="100" fill="#de7b35"/>
<rect x="150" y="340" width="300" height="160" rx="40" fill="#247d83"/>
</svg>
將以下內容儲存為 shapes-wide.svg:
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="600" viewBox="0 0 1200 600">
<rect width="1200" height="600" fill="#fff5df"/>
<circle cx="320" cy="300" r="180" fill="#de7b35"/>
<rect x="650" y="150" width="400" height="300" rx="60" fill="#247d83"/>
</svg>
儲存 HTML 頁面
在同一個資料夾中建立 index.html。如果使用 TextEdit,請選擇 檔案 > 新增,再選擇 格式 > 製作純文字,然後貼上程式碼。以 .html 副檔名儲存檔案;如果出現提示,請選擇 使用 .html。Apple 說明了建立 HTML 檔案的這項流程。Apple:在 Mac 上使用 TextEdit 處理 HTML 文件
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shape study</title>
<style>
body { margin: 0; font-family: system-ui, sans-serif; }
main { width: calc(100% - 32px); max-width: 960px; margin: 24px auto; }
picture { display: block; }
.study-image { display: block; width: 100%; height: auto; }
</style>
</head>
<body>
<main>
<h1>Shape study</h1>
<picture>
<source media="(min-width: 700px)" srcset="shapes-wide.svg"
width="1200" height="600">
<img class="study-image" src="shapes-square.svg"
width="600" height="600"
alt="An orange circle and a teal rounded rectangle on cream.">
</picture>
<p>Resize the viewport to compare the two arrangements.</p>
</main>
</body>
</html>
在 Safari 中開啟 index.html。檢視區夠寬時,圖形應該會並排顯示;檢視區較窄時,圖形應該會上下排列。請將三個檔案放在一起:兩個相對資源 URL 會以 HTML 檔案所在位置為基準解析。
寬幅來源使用 srcset,即使它只有一個 URL 也是如此。在 picture 內,source 必須搭配 srcset;不能使用它的 src 屬性。尺寸屬性是沒有單位的整數,因此要使用 width="1200",而不是 width="1200px"。MDN:source 元素
為什麼要同時在來源和後備項目上宣告尺寸?
後備項目的 600 × 600 尺寸描述正方形資源。寬幅來源的 1200 × 600 尺寸則描述寬幅資源。提供這兩組尺寸後,支援此功能的瀏覽器可以在下載圖片前先確定所選圖片的比例。若寬幅來源沿用正方形尺寸,初始長寬比就會不正確。HTML 標準:來源尺寸屬性
接著,CSS 會將圖片寬度設為可用內容區域的寬度,並讓高度保持自動。自動高度可讓圖片比例決定其高度。CSS 尺寸規格草案說明了偏好長寬比如何參與自動尺寸計算;明確固定兩個尺寸則會失去這種彈性。CSS 盒子尺寸模組第 4 級
此範例可透過以下簡單計算檢查版面:
圖片寬度 = min(檢視區寬度 - 32, 960)
正方形高度 = 圖片寬度
寬幅高度 = 圖片寬度 / 2
| CSS 像素的檢視區寬度 | 選取的資源 | 計算出的圖片尺寸 |
|---|---|---|
| 500 | shapes-square.svg |
468 × 468 |
| 699 | shapes-square.svg |
667 × 667 |
| 700 | shapes-wide.svg |
668 × 334 |
| 1000 | shapes-wide.svg |
960 × 480 |
這些是根據所提供 CSS 計算出的預期值,假設捲軸寬度不會減少可用內容區域。SVG 語法、資源名稱、宣告尺寸與算術都已透過程式檢查;編寫期間並未在瀏覽器中實際呈現此範例。
請留意 699px 與 700px 之間高度的大幅變化。這是從正方形構圖切換到寬幅構圖的直接結果。調整大小時出現這種變化是預期現象。如果檢視區固定不動,載入後又出現第二次跳動,就應檢查宣告尺寸以及是否有 CSS 規則覆寫它們。
在 Safari 中精確測試斷點
Safari 的「回應式設計模式」可讓你獨立於桌面視窗調整頁面檢視區大小。在 Safari 的「進階」設定中,啟用「顯示網頁開發者功能」。開啟範例後,選擇 開發 > 進入回應式設計模式,或按下 Control-Command-R。WebKit 說明了此設定、快速鍵和可調整大小的預覽畫面。WebKit:簡化的回應式設計模式
先測試 699px 和 700px,接著測試一個足夠窄和一個足夠寬的檢視區。確認構圖在預定邊界切換、橙色圖形維持圓形,而且圖片下方的段落會配合圖片高度變化。分別在斷點兩側重新載入,檢查初始版面與調整大小時的結果。
若要直接確認 Safari 選取了哪個檔案,可在檢視範例時,於 Web Inspector 的主控台執行以下選用的診斷程式碼:
const studyImage = document.querySelector('.study-image');
if (!studyImage) {
throw new Error('Open the Shape study example before running this snippet.');
}
const studyBox = studyImage.getBoundingClientRect();
console.table({
selectedURL: studyImage.currentSrc,
displayedWidth: studyBox.width,
displayedHeight: studyBox.height
});
跨越斷點後再次執行程式碼。選取的 URL 應以對應的正方形或寬幅檔名結尾。currentSrc 屬性會回報瀏覽器選擇的 URL;單靠它的值無法證明資源已成功載入。MDN:HTMLImageElement currentSrc 屬性
切換結果不如預期時要檢查什麼?
依序檢查選取結果、資源尺寸和呈現方式。這樣可以避免把 CSS 尺寸問題誤認為資源選取問題。
- 寬螢幕下仍選取正方形檔案。 確認檢視區達到
700px、source排在img之前,而且來源使用srcset。有多個來源時,請檢查它們的順序:較早出現且符合條件的來源可能會優先採用。HTML 標準:藝術指導選取 - 資源沒有顯示。 比對標記中的檔名與資料夾內的檔案,包括副檔名。此範例的兩個 SVG 檔案都必須放在
index.html旁邊。 - 顯示了正確資源,但形狀錯誤。 檢查套用於實際
img的 CSS,尤其是指定固定高度的規則。要按比例調整尺寸,請恢復height: auto。 - 圖片載入後跳動。 比較每組宣告尺寸與資源的實際比例。也請檢查是否有明確的 CSS
aspect-ratio覆寫了預期比例。
如果實際設計需要固定框架,請慎選填入方式。object-fit: contain 會保留完整資源,可能留下空白;cover 會填滿框架,也可能裁切內容;fill 則可能拉伸內容。請將填入屬性套用於 img。此範例不需要固定框架,因為版面會隨所選資源的比例調整。MDN:object-fit
瀏覽器支援有哪些限制?
對 picture 的支援與對來源專屬尺寸的支援,是兩個不同的考量。HTML 標準的相容性摘要列出目前瀏覽器引擎中的 picture。MDN 將反映尺寸屬性的來源 width 屬性標示為自 2022 年 12 月起已獲各瀏覽器支援。不可假設舊版瀏覽器能正確保留來源專屬尺寸。HTML 標準:picture 元素、MDN:HTMLSourceElement width 屬性
如果沒有來源符合條件,或瀏覽器不支援 picture,後備 img 會提供圖片。此範例使用的是正方形構圖。能切換資源、但不支援來源尺寸的瀏覽器,可能要等圖片載入後才能確定寬幅圖片的最終比例。MDN:picture 元素
如果目標瀏覽器支援 CSS aspect-ratio,但需要明確的尺寸規則,請將以下 CSS 片段附加到現有樣式表。它會比照 HTML 斷點,提供暫定比例,同時允許載入圖片後改用其自然比例:
.study-image {
aspect-ratio: auto 1 / 1;
}
@media (min-width: 700px) {
.study-image {
aspect-ratio: auto 2 / 1;
}
}
MDN 說明了 auto 與比例搭配使用的方式,並列出自 2021 年 9 月起已獲各瀏覽器支援的 CSS aspect-ratio。因此,此片段也有自身的支援範圍。請讓片段中的斷點與來源條件保持一致,並測試你實際需要支援的瀏覽器版本。MDN:aspect-ratio
範例正常運作後,請將合成檔案換成自己的構圖,並一併更新尺寸。保持來源條件、資源比例與 CSS 尺寸設定一致,然後在斷點正下方與正上方重新執行檢查。
來源
- HTML 標準:圖片 — WHATWG
- HTML 標準:嵌入內容 — WHATWG
- CSS 盒子尺寸模組第 4 級 — W3C CSS 工作小組
<picture>:Picture 元素 — MDN Web Docs<source>:媒體或圖片來源元素 — MDN Web Docs- HTMLSourceElement:width 屬性 — MDN Web Docs
- HTMLImageElement:currentSrc 屬性 — MDN Web Docs
- object-fit CSS 屬性 — MDN Web Docs
- aspect-ratio CSS 屬性 — MDN Web Docs
- 在 Mac 上使用 TextEdit 處理 HTML 文件 — Apple
- 簡化的回應式設計模式 — WebKit