在 SVG <symbol> 中定義一次圖形,再於每個可見的 SVG 中使用 <use> 參照其 ID。為每個實例設定個別尺寸,並讓 CSS 排列周圍的頁面內容。SVG 文件結構。
本教學適合在 Mac 上編輯 HTML 頁面,並希望在數個文字標籤旁放置同一個小圖形的人。完整範例使用合成圖塊、一般 HTML 和 CSS。不需要框架、JavaScript、下載的圖稿或建置步驟。
一個符號如何產生多個可見圖形?
<symbol> 是圖形範本。它本身不會顯示;<use> 參照會建立可見實例。將定義放在文件中一次,然後在圖形要出現的地方加入小型 SVG 包裝元素。MDN 指出這兩個元素都已廣泛支援。MDN:symbol。
重要的是要區分避免重複撰寫路徑與避免瀏覽器的繪製工作。你的 HTML 只包含一個路徑定義,但瀏覽器仍會為每個 <use> 建立一個繪製實例。MDN 將此描述為複製到未公開的 DOM 中。重複使用能讓原始碼更容易維護;這不代表多個可見圖形會變成同一個繪製物件。MDN:use。
若頁面有標籤和圖示,請將標籤保留在 HTML 中,並為每個圖示提供自己的 SVG 包裝元素。WHATWG 將 SVG 視為 HTML 中的嵌入式、措辭內容和流式內容,因此可將這些包裝元素放在一般頁面內容之間。HTML 標準:SVG。
建立只有一個定義、三個實例的完整頁面
在 Mac 上使用純文字編輯器建立名為 svg-reuse.html 的檔案。貼上以下完整文件並儲存,再用桌面瀏覽器開啟。保留 .html 副檔名,並以純文字而非豐富文字文件儲存。
此範例使用單一 <path> 定義兩個對角圖塊。三個參照以不同尺寸和顏色顯示相同幾何圖形。每個參照都使用 href="#demo-tiles";目前的寫法是純 href,而 xlink:href 已遭棄用。MDN:use 屬性。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Reusable tile symbol</title>
<style>
body {
margin: 2rem;
font-family: system-ui, sans-serif;
color: #263445;
}
.symbol-bank {
position: absolute;
width: 0;
height: 0;
overflow: hidden;
}
.samples {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
}
.sample {
display: flex;
align-items: center;
gap: 0.75rem;
padding: 1rem;
border: 1px solid #cbd5df;
}
.icon {
display: block;
width: 24px;
height: 24px;
flex: none;
}
.icon-large { width: 48px; height: 48px; }
.icon-medium { width: 32px; height: 32px; }
.blue { color: #2457a7; }
.purple { color: #7140a0; }
</style>
</head>
<body>
<svg class="symbol-bank" width="0" height="0" aria-hidden="true">
<symbol id="demo-tiles" viewBox="0 0 24 24"
preserveAspectRatio="xMidYMid meet">
<path fill="currentColor"
d="M4 4H10V10H4Z M14 14H20V20H14Z"></path>
</symbol>
</svg>
<main>
<h1>Tile samples</h1>
<div class="samples">
<div class="sample">
<svg class="icon" width="24" height="24"
viewBox="0 0 24 24" aria-hidden="true">
<use href="#demo-tiles" width="24" height="24"></use>
</svg>
<span>Small tiles</span>
</div>
<div class="sample blue">
<svg class="icon icon-large" width="48" height="48"
viewBox="0 0 24 24" aria-hidden="true">
<use href="#demo-tiles" width="24" height="24"></use>
</svg>
<span>Large tiles</span>
</div>
<div class="sample purple">
<svg class="icon icon-medium" width="32" height="32"
viewBox="0 0 24 24" aria-hidden="true">
<use href="#demo-tiles" width="24" height="24"></use>
</svg>
<span>Medium tiles</span>
</div>
</div>
</main>
</body>
</html>
預期結果是三個帶框範例,內含相同的對角圖塊。第一個使用本文文字顏色,第二個為藍色,第三個為紫色。它們的 SVG 方框尺寸分別為 24、48 和 32 CSS 像素。縮窄瀏覽器視窗,檢查範例如何換行。
這裡的可見形狀屬於裝飾,因為相鄰標籤已提供內容。因此 SVG 包裝元素使用 aria-hidden="true"。這會將它們從無障礙樹中移除,但不會在視覺上隱藏。請只對裝飾圖形採用此處理方式;若圖像承載了文字中沒有的資訊,就不要這樣處理。MDN:aria-hidden。
哪些設定控制頁面配置,哪些控制 SVG 配置?
這裡有三項不同的工作:排列 HTML 元件、設定每個 SVG 方框的尺寸,以及將圖畫映射到方框中。改變其中一項工作的設定,可能不會影響另外兩項。
| 工作 | 範例中的設定 | 要變更的內容 |
|---|---|---|
| 在頁面上排列範例 | .samples 使用 flexbox 和換行 |
在此變更間距或換行方式 |
| 將每個圖形與其標籤對齊 | .sample 使用 flexbox 和 align-items: center |
在此變更元件的對齊方式 |
| 設定顯示的 SVG 方框 | .icon 及其尺寸類別 |
在此變更 CSS 寬度和高度 |
| 定義圖畫座標 | viewBox="0 0 24 24" |
圖稿的座標範圍改變時,在此變更 |
| 設定參照符號的內部尺寸 | <use> 的寬度和高度為 24 |
讓這些值與此範例的內部座標區域相符 |
| 按比例縮放圖畫 | preserveAspectRatio="xMidYMid meet" |
只有在需要不同的適配行為時才變更 |
Flexbox 會排列彈性容器的直接子元素。因此,外層容器會排列各個範例,每個內層容器則會將 SVG 排在標籤旁。Flexbox 一次沿一個維度運作;換行後的各行會各自分配空間。若設計需要協調排列列與欄,CSS Grid 是合適的頁面配置替代方案。MDN:flexbox 基本概念。
在 SVG 內,<use> 使用不同的配置模型。它的 x 和 y 值會在 SVG 座標系統中偏移圖形,不會設定 HTML 元件之間的間距。它的寬度和高度可以設定參照符號的視埠尺寸;對於直接參照的路徑或群組,這些值並非通用的縮放控制項。W3C:重複使用圖形的配置。
為什麼較大的實例仍使用 24 的內部尺寸?
外層 SVG 的 viewBox 描述一個 24 乘 24 的座標區域。它的 CSS 方框可以是 48 乘 48 像素,內部座標則維持不變。<use> 會填滿這個內部的 24 乘 24 區域,而外層 SVG 會將它映射到較大的顯示方框。MDN 將 viewBox 定義為四個數值:最小 x、最小 y、寬度和高度。MDN:viewBox。
以這份圖稿做示意計算,48 像素的方框會將 24 個座標單位映射成 48 / 24 = 2 的比例。圖塊幾何範圍從座標 4 延伸到 20,因此整體著色範圍會變成 (20 - 4) × 2 = 32 像素。其餘空間來自圖畫內刻意保留的邊界。
這說明了為什麼增加圖示的 CSS 寬度,不一定會讓著色形狀填滿整個寬度。調整頁面邊界來補償之前,請先檢查 viewBox 內幾何圖形的範圍。
在矩形 SVG 方框中會發生什麼事?
使用 xMidYMid meet 時,圖畫會等比例縮放、維持置中,並完整置於可用的視埠內。因此,正方形圖畫放在寬矩形中時,兩側會留下空間。none 允許變形;slice 會維持比例,但讓 viewBox 的部分區域超出視埠。若要讓完整圖形保持可見,請使用 meet。MDN:preserveAspectRatio。
如何為每個實例設定不同顏色?
路徑使用 fill="currentColor"。這個關鍵字會採用元素的 color 值,讓同一個圖畫能跟隨周圍文字的顏色。在範例中,變更 .blue 或 .purple 規則,會同時改變標籤和圖塊。MDN:currentColor 關鍵字。
這是透過繼承進入每個實例而運作的。SVG 的重複使用模型會讓產生的內容繼承 <use> 宿主元素的樣式。直接在來源路徑上宣告的固定顏色,會優先於父元素提供的繼承填色。若需要為每個實例設定不同顏色,請勿在共用幾何圖形上指定固定顏色。W3C:樣式範圍與繼承。
避免依賴 .blue path 之類的選取器,透過可見包裝元素去選取產生的路徑。產生的內容屬於重複使用的陰影樹,因此祖先關係與一般巢狀 HTML 不同。請在包裝元素或其容器上設定 color,並在來源幾何圖形中保留 currentColor。W3C:樣式範圍與繼承。
重複使用的符號顯示異常時,該檢查什麼?
從參照開始往外檢查。這個順序能區分圖形缺失與尺寸或位置不正確,讓每次調整都能針對特定機制。
- 檢查目標。 確認
href="#demo-tiles"與定義中的id="demo-tiles"相符。確保該 ID 在文件樹中唯一。W3C:id 屬性。 - 檢查可見包裝元素的尺寸。
.symbol-bank類別只應用於定義容器,並保持零尺寸。每個可見實例都需要非零方框,如.icon所示。 - 檢查座標範圍。 確認圖稿位於宣告的
viewBox範圍內。多餘的空白可能來自未使用的圖畫座標。MDN:viewBox。 - 檢查參照元素類型。 若你將符號換成直接路徑參照,變更
<use>的寬度和高度,不會以相同方式縮放路徑。若要採用此模式,請還原符號及其viewBox。MDN:use。 - 檢查顏色宣告。 加入更多實例選取器之前,先查看來源中是否有固定顏色。
- 檢查頁面容器。 若圖形能正確繪製,但與標籤距離過遠,請調整元件的 CSS 間距或對齊方式。MDN:flexbox 基本概念。
將範例整合到現有頁面時,只需插入一次符號庫、合併 CSS,並將可見 SVG 包裝元素複製到其他元件。這份小型文件已進行結構檢查,確認元素配對、ID 唯一,以及三個參照都指向同一個路徑定義;這些檢查無法證明瀏覽器中的實際呈現效果。請在打算支援的 Mac 瀏覽器中開啟頁面,檢查顯示後的尺寸、間距和顏色。
若要變更共用圖畫,請編輯唯一的路徑定義。若要變更單一實例,請編輯其包裝元素的尺寸或繼承顏色。讓這些工作各自分明,就能重複使用圖稿,並預期各個實例會出現在指定位置。
來源
- 文件結構 — SVG 2 — W3C。
- HTML 標準,網頁開發者版:SVG — WHATWG。
<symbol>— MDN Web Docs。<use>— MDN Web Docs。- flexbox 基本概念 — MDN Web Docs。
- viewBox — MDN Web Docs。
- preserveAspectRatio — MDN Web Docs。
<color>CSS 類型 — MDN Web Docs。- ARIA:aria-hidden 屬性 — MDN Web Docs。