跳到主要内容

符号复用与use

symbol 定义一份几何;use 实例化。生产默认是 同文档 inline sprite,不是每个图标一个 HTTP,也不是外部 use

1. symbol + use

<svg>
<defs>
<symbol id="plus" viewBox="0 0 24 24">
<path d="M11 5h2v14h-2zM5 11h14v2H5z"/>
</symbol>
</defs>
<use href="#plus" x="8" y="8" width="24" height="24" fill="currentColor"/>
</svg>

新代码用 hrefxlink:href 只在读入旧文件时识别,写出时改写掉。

export function instantiateSymbol(
parent: SVGElement,
symbolId: string,
box: { x: number; y: number; width: number; height: number },
): SVGUseElement {
const use = document.createElementNS("http://www.w3.org/2000/svg", "use");
use.setAttribute("href", `#${symbolId}`);
use.setAttribute("x", String(box.x));
use.setAttribute("y", String(box.y));
use.setAttribute("width", String(box.width));
use.setAttribute("height", String(box.height));
parent.append(use);
return use;
}

symbol 自己不画。缺 viewBoxusewidth/height 对不齐,图标会被切片或挤扁。实例要缩放,靠 use 的宽高或外层 transform,不要去改 symbol 内部数字。

fill 写在 use 上能覆盖 内部未指定 fill 的图形(通过继承)。内部写死 #000 的 path 不会跟主题走——sprite 源文件用 currentColor 或留 fill="inherit"

2. Shadow tree

SVG 2 把 use 的克隆做成 shadow tree(闭包)。后果:

  • use.querySelector("path") 拿不到实例内部。不要靠穿透 DOM 去改「这一个」叶子。
  • 事件在宿主 use 上重定向。监听绑在 use 上,不要绑 symbol 里的节点。
  • 实例特定样式:改 use 的 presentation / CSS 类。必须每实例不同几何时,那就不是 symbol 问题,应该复制成真正的 DOM。

Chrome / Firefox / Safari 对 shadow 封闭性、CSS ::partgetBBox 是否含 clone 仍有差。生产把 use原子图元:命中、选中、变换都以 use 为对象。

3. 外部 use:不要当默认

href="https://cdn.example/icons.svg#plus"href="/sprite.svg#plus"

  • 跨域必须 CORS,失败时静默空白。
  • 历史 WebKit / Safari 对外部 use 支持差,同一文档引用才稳。
  • sprite 文件里的脚本 / 样式与 inline 同一 XSS 面,CDN 不等于沙箱。

适用:同源、且你已为最差引擎做过功能检测的内部工具。
不适用:对外产品图标系统、邮件、要离线的编辑器文档。

4. Inline sprite 是生产默认

把所有 symbol 放进页面里一棵隐藏 &lt;svg>display: none 会让部分引擎 getBBox 异常,更稳是 width="0" height="0" aria-hidden="true" 且仍在文档里),或直接放在用到它的那棵图的 &lt;defs>

方案适用不适用
同文档 &lt;symbol> + &lt;use href="#id">图标、可复用节点模板每实例要改内部几何
复制节点 / 自建 path编辑器里的真正对象工具栏 200 个静态 icon
外部 use受控同源实验默认交付路径
<img src="icon.svg">静态、无需改色、无需命中内部currentColor、要无障碍树

同一 symbol 实例化成千上万次仍是成千上万个 use 节点。节点成本见 06 性能,sprite 只省重复几何和 HTTP,不省 DOM。

5. 失败形态

症状原因
图标空白外部 use CORS / Safari;或 href 写成 xlink:href 且无 NS
改 use 的 fill 不变色symbol 内部写死了 fill
querySelector 找不到 pathshadow tree 封闭
display:none 的 sprite 实例尺寸为 0none 的祖先连累,sprite 应从渲染树「看不见」但仍挂载
点选进了「内部 path」状态没把 use 当原子,去穿透 shadow

权威资料

核对日期:2026-08-26