在 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 标准,Web 开发者版: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。