若要移除 SVG use 實例周圍意外出現的空白,請確認空白是來自來源 viewBox、長寬比適配,還是周圍 CSS 行框。本指南說明如何診斷並修正各種成因,同時讓定位座標維持可預測。
這項任務是簡單的桌面網頁編輯:在 SVG 內精確定位可重複使用的形狀,然後讓周圍的 HTML 版面符合預期。你可以在 Mac 上使用純文字編輯器參照範例操作,再用目前版本的桌面瀏覽器開啟儲存的 HTML 檔案。
哪個座標系統控制空白?
有三個邊界需要檢查:外層 SVG 元素的 CSS 方框、被參照符號使用的視埠,以及該符號內的實際形狀。W3C 明確區分 SVG 視埠與瀏覽器的 CSS 視埠。viewBox 會將 SVG 使用者座標映射至 SVG 視埠;它描述的不是瀏覽器視窗。座標系統、轉換與單位 — SVG 2
例如,x="20" 在 use 元素上提供的是 SVG 座標系統中的位移,不代表距離瀏覽器視窗左邊緣 20 個 CSS 像素。縮放和祖先元素的轉換會改變該位移在頁面上的呈現位置。SVG 規範將 use 定位描述為額外的平移,其行為與 CSS 方框版面配置不同。文件結構 — SVG 2
先參考這份判斷表。這是一套依據文件所述版面配置機制整理的診斷流程,不是可互換使用的修正方法清單。
| 觀察到的現象 | 優先檢查項目 | 可能的修正方式 |
|---|---|---|
| 整個 SVG 下方出現一條窄空白 | 行內排版與父元素的行高 | 將獨立 SVG 設為區塊層級,或調整其行內對齊方式 |
| 每個重複圖形內都有空白 | 形狀座標與符號的 viewBox |
若內縮並非預期,請收緊來源邊界 |
| 符號實例兩側多出空白 | 實例尺寸與 viewBox 長寬比 |
讓兩者長寬比相符,或選擇明確的適配方式 |
| 區域內位置正確,但頁面位置錯誤 | SVG 使用者單位與瀏覽器視埠座標 | 指定 x 和 y 前先轉換座標 |
| 調整實例尺寸沒有作用 | href 指向的元素 |
使用能定義視埠的符號來進行適配,或轉換幾何圖形 |
使用完整的本機範例重現空白
在純文字編輯器中將以下完整文件儲存為 svg-spacing.html,然後用瀏覽器開啟。範例只使用示意標籤和矩形,不需要任何函式庫或外部檔案。淺色矩形標示預期的實例視埠;深色矩形則是重複使用的圖稿。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SVG spacing example</title>
<style>
body {
margin: 24px;
font: 16px system-ui, sans-serif;
}
#canvas {
display: block;
width: 320px;
height: 200px;
outline: 1px solid #687580;
background: #fff;
}
.viewport-guide { fill: #e4edf2; }
.artwork { fill: #356b8c; }
text { fill: #253744; font-size: 14px; }
</style>
</head>
<body>
<p>Two instances with different source bounds and fitting dimensions.</p>
<svg id="canvas" xmlns="http://www.w3.org/2000/svg"
width="320" height="200" viewBox="0 0 320 200"
role="img" aria-labelledby="drawing-title">
<title id="drawing-title">Padded and tightly fitted rectangles</title>
<defs>
<symbol id="padded" viewBox="0 0 100 100">
<rect id="source-shape" class="artwork"
x="20" y="20" width="60" height="60" />
</symbol>
<symbol id="tight" viewBox="20 20 60 60">
<rect class="artwork"
x="20" y="20" width="60" height="60" />
</symbol>
</defs>
<rect class="viewport-guide"
x="20" y="20" width="120" height="60" />
<use href="#padded" x="20" y="20" width="120" height="60" />
<text x="160" y="55">Padded source</text>
<rect class="viewport-guide"
x="20" y="110" width="60" height="60" />
<use id="tight-instance" href="#tight"
x="20" y="110" width="60" height="60" />
<text x="110" y="145">Tight source</text>
</svg>
</body>
</html>
兩個實例都明確設定了尺寸,避免排查空白時依賴隱含尺寸。MDN 說明 use 會重複使用被參照的 SVG 內容,也指出當目標是具有 viewBox 的 SVG 或符號時,其 width 和 height 會影響適配。範例使用目前的 href 屬性。MDN:use
計算第一個矩形實際開始的位置
第一個來源的 viewBox 為 100 × 100,但其矩形只占用各方向上從 20 到 80 的座標。指定的實例視埠為 120 × 60。使用預設的 xMidYMid meet 適配方式時,縮放比例是 120 / 100 和 60 / 100 中較小的值:0.6。縮放後的 viewBox 占 60 × 60,因此左右各留出 30 個單位。這符合 W3C 的視埠轉換演算法。SVG 2:計算 SVG 視埠的等效轉換
以這些示意輸入值計算,繪製出的矩形從水平位置 20 + 30 + 20 × 0.6 = 62 和垂直位置 20 + 20 × 0.6 = 32 開始。其各方向尺寸都是 60 × 0.6 = 36。這些數值已透過簡單的確定性計算檢查;它們是計算結果,不是瀏覽器測試的測量值。
第二個實例修改了兩個互不相關的輸入值:來源邊界變為 20 20 60 60,而實例視埠變為 60 × 60。因此矩形會填滿該視埠,並從 SVG 座標 (20, 110) 開始。若要自行分辨成因,請一次只改一個輸入值。
如何移除實例內部的空白?
修正來源邊界中非預期的空白
viewBox 包含四個數值:最小 x、最小 y、寬度和高度。其原點不必是零。範例中的 viewBox="20 20 60 60" 描述矩形現有的邊界,不必重寫幾何圖形。MDN:viewBox
收緊實際圖形的邊界前,請先判斷其內縮是否為刻意設計。一組可重複使用的形狀可能會共用同一個座標框架,以確保視覺尺寸和位置一致。如果分別收緊每個符號,可能會改變這些關係。若共用邊界是設計一致性的一部分,就請保留它們。
檢查幾何圖形時,getBBox() 會回報 SVG 使用者座標中的邊界。預設情況下,它會排除筆畫和標記,也不會計入套用至目標元素或其父元素的轉換。因此,純填色的外框不足以作為裁切帶有筆畫或經過轉換圖稿的依據。MDN:SVGGraphicsElement getBBox()
選擇長寬比不符時的適配方式
即使圖稿邊界緊貼內容,將正方形來源放進寬幅視埠時,周圍仍可能出現空白。請依預期結果選擇適配方式。若要調整符號內部的適配,請對被參照的符號套用 preserveAspectRatio;若要診斷外層座標映射,則套用在外層 SVG 上。MDN:preserveAspectRatio
| 選項 | 結果與條件 |
|---|---|
| 來源與視埠的長寬比相符 | 保留原有比例,同時避免因適配長寬比產生空白 |
xMidYMid meet |
顯示整個 viewBox 並置中;長寬比不符時會留下空白 |
xMinYMin meet |
將適配後的 viewBox 移至靠近左上角的位置;仍會有剩餘空白 |
none |
允許非等比縮放;正方形可能會變成矩形 |
xMidYMid slice |
填滿視埠,但部分來源內容會超出視埠;可見範圍由裁切決定 |
改變對齊方式只會移動適配產生的空白,不會移除來源幾何圖形中原本就有的內縮。同樣地,若必須讓所有來源內容都留在視埠內,就不適合使用 slice。這些差異符合 MDN 對對齊方式、meet、slice 和非等比適配的定義。MDN:preserveAspectRatio
當尺寸看似無效時,檢查參照目標
單純的群組或路徑不會只因為被 use 元素參照,就取得可用於適配的視埠。W3C 指出,當被參照的元素不會建立新的視埠時,實例的 width 和 height 不會生效。若要讓每個實例都能預測地適配,請像上面的範例一樣,將可重複使用的幾何圖形放入具有明確邊界的符號中。若要直接縮放幾何圖形,請使用轉換並將其對定位造成的影響納入考量。SVG 2:重複使用圖形的版面配置
如何移除外層 SVG 下方的空白條?
SVG 外部的空白可能來自 HTML 行內排版。WHATWG 允許在片語內容中使用 SVG,因此周圍頁面可以將它與文字並排放置。CSS 行框會在基線上方和下方納入字型度量值,因此行內圖形的方框下方可能出現可見空白。HTML 標準:SVG、CSS 2:行高計算
完整範例已將 display: block 設定在 #canvas 上,讓 SVG 不再參與行內行框。若是獨立圖形,請保留這項設定。若要了解其運作方式,可暫時改為 display: inline,然後檢查周圍的行框。
若 SVG 必須與文字並排,請嘗試對外層 SVG 設定 vertical-align: bottom,再檢查文字對齊結果。這個屬性會調整行內層級方框在其行框中的位置,不會改變符號邊界或內部適配。其他內容和父元素的行高仍可能決定整個行框的高度。MDN:vertical-align
以下 CSS 宣告是外層 SVG 的替代設定,不是要貼到每個實例上的累加修正方式:
/* Standalone drawing */
#canvas {
display: block;
}
/* Alternative when the drawing must stay inline */
/*
#canvas {
display: inline;
vertical-align: bottom;
}
*/
如果座標來自瀏覽器視埠,該怎麼辦?
getBoundingClientRect() 會以 CSS 像素回報元素相對於瀏覽器視埠的位置。頁面捲動時,這些數值也會改變。這些值屬於不同於 SVG 使用者座標的空間,因此通常不能直接將 left 和 top 複製到實例的 x 和 y 中。MDN:Element getBoundingClientRect()
若輸入的是瀏覽器視埠中的點,請使用座標轉換。getScreenCTM() 會提供 SVG 轉換矩陣,套用其反矩陣即可將該點轉回所選元素的本機座標。點的 matrixTransform() 方法可以執行轉換。MDN:getScreenCTM()、MDN:matrixTransform()
以下主控台程式碼是對上方完整文件的選用擴充。它會將瀏覽器視埠座標點 (100, 150) 轉換為外層 SVG 的使用者座標,並將邊界貼合內容的實例移至該處。此程式碼假設範例中未經轉換的實例仍是該 SVG 的直接子元素。
(() => {
const canvas = document.getElementById("canvas");
const instance = document.getElementById("tight-instance");
if (!canvas || !instance) {
throw new Error("Open the complete SVG spacing example first.");
}
const matrix = canvas.getScreenCTM();
if (!matrix) {
throw new Error("The SVG coordinate matrix is unavailable.");
}
const viewportPoint = new DOMPoint(100, 150);
const localPoint = viewportPoint.matrixTransform(matrix.inverse());
if (!Number.isFinite(localPoint.x) || !Number.isFinite(localPoint.y)) {
throw new Error("The SVG coordinate matrix cannot be inverted.");
}
instance.setAttribute("x", String(localPoint.x));
instance.setAttribute("y", String(localPoint.y));
})();
有限數值檢查很重要,因為不可逆矩陣會產生 NaN 分量。版面配置或捲動狀態改變後,若要轉換新的點,請重新計算矩陣。如果實例位於經過轉換的群組內,請改為轉換至該父群組的座標系統。研究期間已根據 API 文件檢查此程式碼片段,但未在瀏覽器中執行。MDN:DOMMatrixReadOnly inverse()
最後,分別檢查三個邊界:外層 SVG 方框、符號的適配視埠,以及圖稿本身的邊界。修正引入非預期空白的邊界,再確認結果符合預期頁面尺寸。如此便能讓定位維持可預測,不必用任意位移補償原因不明的空白。
來源
- 座標系統、轉換與單位 — SVG 2 — W3C。
- 文件結構 — SVG 2 — W3C。
use— MDN Web Docs。- viewBox — MDN Web Docs。
- preserveAspectRatio — MDN Web Docs。
- SVGGraphicsElement:getBBox() 方法 — MDN Web Docs。
- HTML 標準 — SVG — WHATWG。
- 視覺格式模型詳細說明 — W3C。
- vertical-align CSS 屬性 — MDN Web Docs。
- Element:getBoundingClientRect() 方法 — MDN Web Docs。
- SVGGraphicsElement:getScreenCTM() 方法 — MDN Web Docs。
- DOMPointReadOnly:matrixTransform() 方法 — MDN Web Docs。
- DOMMatrixReadOnly:inverse() 方法 — MDN Web Docs。