要預測響應式圖片候選項,請將 sizes 解析為 CSS 寬度,乘以裝置像素比,並將該目標值與 srcset 比較。接著確認所選 URL:瀏覽器保留最終選擇的裁量權。
本指南適合在 Mac 上使用 Chrome 檢查自行編寫的網頁的人。你將計算可能的候選項、測試包含原創抽象形狀的本機頁面,並區分誤導性的尺寸宣告與瀏覽器正常的選擇行為。
sizes、srcset 和 DPR 分別向瀏覽器提供什麼資訊?
使用寬度描述符時,srcset 會列出可用資源及其固有像素寬度。像 800w 這樣的描述符,必須表示實際寬度為 800 像素的圖片。請將寬度描述符和像 2x 這樣的密度描述符分開放在不同的來源集;在同一個 srcset 中混用兩者是無效的。MDN 的圖片元素參考文件說明了這些要求。
sizes 提供資源選擇時預期的顯示寬度。瀏覽器會依序評估其中的條件,並使用第一個符合的項目。請將無條件的後備值放在最後。來源尺寸可接受 480px、50vw 和 calc(100vw - 32px) 等長度;像 50% 這樣的百分比值不是有效的版位寬度。在 HTML 中使用響應式圖片
CSS 控制顯示尺寸。請將 CSS 和明確的 sizes 清單視為兩項必須保持一致的描述:其中一項決定版面配置,另一項則提供資源選擇資訊。單獨變更 sizes 並不會實作對應的版面配置。HTML 標準:sizes 屬性
DPR 描述實體像素與 CSS 像素之間的關係。請讀取 window.devicePixelRatio,不要根據 Mac 型號或顯示器名稱猜測數值。頁面縮放可能會改變這個值,在不同顯示器之間移動視窗也可能改變它。雙指縮放不會改變 DPR。MDN:Window.devicePixelRatio
如何計算可能的候選項?
對於解析後的來源尺寸 S、資源寬度 W 和 DPR D,可使用以下兩種等效計算方式:
目標資源寬度 = S × D
候選項有效密度 = W ÷ S
HTML 處理模型會將每個候選項的寬度除以來源尺寸,藉此正規化寬度描述符。MDN 也說明了實用的預測方式:將尺寸提示乘以 DPR。HTML 標準:正規化來源密度、MDN:HTMLImageElement.sizes
實用的估算方式是選擇大於或等於目標寬度的最小候選項。如果所有候選項都小於目標值,請指出可用的最大候選項並記錄差距。以下練習將明確採用這項預測規則。HTML 標準將最終選擇留給實作決定,並未要求所有瀏覽器都遵循這項取整規則。HTML 標準:選擇圖片來源
考慮以下來源尺寸清單,以及 480w、800w、1200w 和 1440w 候選項:
(max-width: 600px) calc(100vw - 32px),
(max-width: 1200px) calc(50vw - 32px),
568px
100vw 表示視埠寬度,50vw 表示該寬度的一半。這些單位參照的是視埠,而非圖片的父容器。CSS 值與單位:視埠百分比長度
下表列出的是示意計算結果,並非記錄到的瀏覽器結果。最後一欄依照上述預測規則得出。
| 視埠寬度,CSS px | DPR | 解析後的來源尺寸,CSS px | 目標資源寬度,px | 預測候選項 |
|---|---|---|---|---|
| 600 | 1 | 568 | 568 | 800w |
| 600 | 2 | 568 | 1,136 | 1200w |
| 601 | 2 | 268.5 | 537 | 800w |
| 1,000 | 1 | 468 | 468 | 480w |
| 1,000 | 2 | 468 | 936 | 1200w |
| 1,400 | 2 | 568 | 1,136 | 1200w |
| 1,400 | 3 | 568 | 1,704 | 1440w,低於目標 |
從 600 到 601 CSS 像素的轉變尤其適合測試。在 600 時,第一個條件提供幾乎全寬的版位;在 601 時,第二個條件提供窄得多的版位。因此,視埠變寬反而會產生較小的目標圖片。這直接源自自行編寫的版面配置約定。
視埠寬度為 1,000 像素、DPR 為 2 時,來源尺寸是 468 CSS 像素。四個候選項的有效密度約為 1.03x、1.71x、2.56x 和 3.08x。依照我們的預測規則,1200w 候選項是第一個超過 2x 目標密度的項目。
如何建立完整的本機測試?
請使用安裝了 Chrome 和 Python 3.8 或更新版本的 Mac。在純文字編輯器中,將以下完整程式儲存為 responsive_demo.py。程式會產生四個包含相同矩形與圓形的 PNG 檔案、寫入相符的網頁,並啟動本機伺服器。所有產生的檔案都會放進新的暫存目錄,因此不會覆寫現有檔案。
此頁面刻意使用立即載入的圖片和明確的來源尺寸。其 CSS 寬度與計算表中的三個分支一致。伺服器使用 Python 文件記載的 ThreadingHTTPServer 和目錄型請求處理器。Python:http.server
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
import struct
import tempfile
import zlib
def chunk(kind, data):
return (
struct.pack("!I", len(data)) + kind + data
+ struct.pack("!I", zlib.crc32(kind + data))
)
def make_png(width):
height = width // 2
rows = []
for y in range(height):
row = bytearray()
for x in range(width):
color = (242, 244, 248)
if width // 8 <= x < width // 2 and height // 4 <= y < 3 * height // 4:
color = (70, 100, 160)
if (x - 3 * width // 4) ** 2 + (y - height // 2) ** 2 < (height // 5) ** 2:
color = (220, 160, 60)
row.extend(color)
rows.append(b"\x00" + row)
header = struct.pack("!IIBBBBB", width, height, 8, 2, 0, 0, 0)
return (
b"\x89PNG\r\n\x1a\n"
+ chunk(b"IHDR", header)
+ chunk(b"IDAT", zlib.compress(b"".join(rows)))
+ chunk(b"IEND", b"")
)
page = '''<!doctype html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shape A candidate test</title>
<style>
body { margin: 0; padding: 16px; font-family: sans-serif; }
#shape { display: block; width: calc(100vw - 32px); height: auto; }
@media (min-width: 600.01px) {
#shape { width: calc(50vw - 32px); }
}
@media (min-width: 1200.01px) {
#shape { width: 568px; }
}
</style>
<p>Shape A: rectangle and circle</p>
<img id="shape" src="shape-a-800.png" width="1440" height="720"
alt="Blue rectangle and amber circle on a pale background"
srcset="shape-a-480.png 480w, shape-a-800.png 800w,
shape-a-1200.png 1200w, shape-a-1440.png 1440w"
sizes="(max-width: 600px) calc(100vw - 32px),
(max-width: 1200px) calc(50vw - 32px), 568px">
</html>
'''
root = Path(tempfile.mkdtemp(prefix="responsive-shapes-"))
for width in (480, 800, 1200, 1440):
(root / f"shape-a-{width}.png").write_bytes(make_png(width))
(root / "index.html").write_text(page, encoding="utf-8")
handler = partial(SimpleHTTPRequestHandler, directory=str(root))
with ThreadingHTTPServer(("127.0.0.1", 0), handler) as server:
print(f"Files: {root}", flush=True)
print(f"Open http://127.0.0.1:{server.server_port}/", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt:
pass
在終端機中切換到儲存程式的資料夾,然後執行:
python3 responsive_demo.py
在 Chrome 中開啟程式列出的本機網址。測試期間請保持終端機運作;完成後在終端機按下 Control+C。程式會要求一個可用的連接埠,因此請使用它列出的網址,不要假設連接埠號固定。
桌面測試的 CSS 門檻使用 600.01px 和 1200.01px,以配合整數視埠寬度。請測試表中的確切整數值。將範例套用到正式版面配置時,請讓實際 CSS 斷點與來源尺寸條件一致,並納入任何小數寬度的行為。
如何在 Mac 上的 Chrome 中確認選擇結果?
以滑鼠右鍵點按形狀並選取 Inspect,即可開啟 DevTools 並選取其圖片元素。Chrome 說明這是檢查元素及其套用樣式的直接方式。開啟 Chrome DevTools
- 點按
Toggle device toolbar,並在Dimensions下選擇Responsive。 - 將視埠寬度設為
1000。 - 在工具列的
More options選單中,選擇Add device pixel ratio,接著選取 DPR2。 - 如有需要,使用
More options,再選擇Add device type,然後選取Desktop。 - 開啟
Network,啟用Disable cache,並在 DevTools 開啟時重新載入頁面。 - 篩選
shape-a,找出所要求的圖片。
Chrome 在裝置模式指南中說明視埠、DPR 和裝置類型控制項,並在網路功能參考文件中說明快取控制項。
頁面載入後,請在 DevTools 的 Console 中執行以下完整診斷程式碼片段:
(() => {
const image = document.getElementById("shape");
if (!image) throw new Error("The Shape A image was not found.");
const viewport = window.innerWidth;
const slot = window.matchMedia("(max-width: 600px)").matches
? viewport - 32
: window.matchMedia("(max-width: 1200px)").matches
? viewport / 2 - 32
: 568;
console.table({
viewportCSSPixels: viewport,
devicePixelRatio: window.devicePixelRatio,
declaredSlotCSSPixels: slot,
renderedWidthCSSPixels: image.getBoundingClientRect().width,
targetResourcePixels: slot * window.devicePixelRatio,
selectedURL: image.currentSrc,
naturalWidthCSSPixels: image.naturalWidth
});
})();
此程式碼片段只會針對本示範計算宣告的版位;它不是通用的 sizes 剖析器。請比較宣告的版位與呈現寬度,再將所選檔名與預測表比較。
currentSrc 會回報瀏覽器選取的完整 URL。這並不能證明資源已成功載入,因此也請檢查圖片請求和顯示結果。在這個範例中,讀取 src 只會顯示後備屬性。MDN:HTMLImageElement.currentSrc
請勿將 naturalWidth 解讀為 PNG 編碼後的寬度。它是經過密度校正、以 CSS 像素表示的寬度。對於這個受控測試素材,產生檔案的尺寸和檔名可指出其資源寬度。MDN:HTMLImageElement.naturalWidth
在 600 和 601 CSS 像素處分別重複測試,並針對每種條件重新載入頁面。記錄視埠、回報的 DPR、版位、所選檔名,以及請求是否完成。這些記錄有助於區分可重複的全新載入結果,以及已載入頁面在調整尺寸時做出的一連串選擇。
預測結果不符時應檢查哪些項目?
先逐一檢查輸入值,再變更候選項清單:
- 檢查描述符類型。 使用
1x和2x等密度描述符時,請勿透過sizes套用寬度描述符的計算方式。 - 檢查第一個符合的條件。 較早符合的條件優先於後續項目。
- 比較宣告寬度與呈現寬度。
100vw宣告可能會高估受 CSS 限制而只能放在窄欄中的版位。 - 讀取實際 DPR。 頁面縮放或顯示器變更後,再次確認數值。
- 比較受控的重新載入結果。 重複測試時保持相同的視埠、DPR 和載入條件。
- 檢查資源是否可用。 所選 URL 與成功顯示的圖片是兩項不同的觀察結果。
缺少明確的來源尺寸,或來源尺寸無法使用時,HTML 剖析器可能會採用 100vw 作為預設值。這可能會解釋為何窄圖片的目標值出乎意料地大。請提供準確的來源尺寸清單,不要假設瀏覽器會從 CSS 推斷預期的欄寬。HTML 標準:剖析 sizes 屬性
如果頁面使用 picture 元素,請先確認適用哪個來源分支,再計算密度。來源選擇會先於該分支候選項之間的選擇;不同裁切版本屬於這種藝術指導機制。在 HTML 中使用響應式圖片
哪些支援限制會影響這個方法?
MDN 將 sizes 屬性標示為各瀏覽器普遍支援,但這不代表所有較新的關鍵字都同樣受到支援。這裡使用的明確條件提供了直接的測試方式,無須依賴自動尺寸。MDN:HTMLImageElement.sizes
sizes="auto" 對延遲載入圖片有效,能讓選擇程序使用其版面寬度。如果採用此關鍵字,請在 auto 後保留明確的後備尺寸,供不支援此關鍵字的瀏覽器使用,並提供圖片尺寸。若不調整這些前提條件,請勿將它套用到這個立即載入的範例。MDN 的圖片元素參考文件
Chrome 的裝置控制項會在模擬條件下測試 Chrome 的行為,無法證明 Safari 或 Firefox 會選擇哪些候選項。Chrome 也指出裝置模式只是一種近似,因此如果另一個瀏覽器的行為很重要,請直接在該瀏覽器中測試。Chrome DevTools:裝置模式的限制
一項實用的預測應以可供檢查的紀錄收尾:適用的來源集、解析後的來源尺寸、回報的 DPR、計算出的目標值,以及觀察到的 currentSrc。當這些輸入值與自行編寫的版面配置一致時,你就能清楚說明資源選擇結果,並判斷下一步應調整 CSS、sizes 還是可用的圖片寬度。
來源
- HTML 標準 — WHATWG。
- 在 HTML 中使用響應式圖片 — MDN Web Docs。
- HTML 圖片嵌入元素 — MDN Web Docs。
- HTMLImageElement:sizes 屬性 — MDN Web Docs。
- Window:devicePixelRatio 屬性 — MDN Web Docs。
- CSS 值與單位第 4 級 — W3C。
- http.server — HTTP 伺服器 — Python 軟體基金會。
- 開啟 Chrome DevTools — Chrome for Developers。
- 使用裝置模式模擬行動裝置 — Chrome for Developers。
- 網路功能參考文件 — Chrome for Developers。
- HTMLImageElement:currentSrc 屬性 — MDN Web Docs。
- HTMLImageElement:naturalWidth 屬性 — MDN Web Docs。