图标数量少时,每个组件直接引入一个 SVG 很方便。随着后台、工具箱或设计系统不断增加图标,文件请求、重复代码、命名和颜色控制会变得混乱。SVG Sprite 的作用,是把多个图标放进同一个 SVG,通过 symbol 定义,再用 use 重复引用。

SVG Sprite 生成器可以批量读取 SVG,在浏览器本地清理危险节点、处理内部 ID 冲突、预览并生成 inline 与外部文件两种引用代码。源文件不会上传服务器。

symbol 与普通 svg 的区别#

symbol 本身不会直接绘制,需要由 use 实例化。一个基本结构是:

html已剪下 ✓
<svg aria-hidden="true" style="position:absolute;width:0;height:0;overflow:hidden">
  <symbol id="icon-search" viewBox="0 0 24 24">
    <path d="..." />
  </symbol>
</svg>

页面里再写:

html已剪下 ✓
<svg class="icon" aria-hidden="true">
  <use href="#icon-search"></use>
</svg>

viewBox 决定内部坐标和缩放。外层图标只需要设置 CSS 宽高,不应该依赖源文件固定的 width="24" height="24"

为什么不能直接把多个 SVG 粘在一起#

许多设计工具会生成 id="paint0_linear"clip0mask0。每个文件单独使用时没有冲突,但合并进同一文档后,所有 ID 共用一个命名空间。

第二个图标中的 fill="url(#paint0_linear)",可能意外引用第一个图标的渐变。结果通常不是报错,而是颜色、遮罩或裁切悄悄变了,很难排查。

合并时应为每个图标重写内部 ID,并同步修改:

  • url(#id) 渐变、遮罩、滤镜与裁切引用;
  • href="#id" 与旧式 xlink:href
  • 内联 style 中的 URL 引用;
  • 可能重复的 title、desc 与 metadata。

工具会用最终 symbol ID 作为命名空间,例如把 clip0 改成 icon-search-clip0

currentColor 适合单色图标#

把路径的 fillstroke 改成 currentColor 后,图标会继承外层 CSS 的 color

css已剪下 ✓
.icon {
  width: 1.25rem;
  height: 1.25rem;
  color: #0f766e;
}

按钮 hover、禁用状态和深色模式只需要改 color,不必进入 SVG 修改每条 path。

但 currentColor 不适合所有素材。品牌 Logo、多色插画、渐变徽章和依赖不同描边颜色的图标,强制统一后会失去信息。开启前要逐个看预览,渐变和 fill="none" 通常应保留。

Inline Sprite 与外部文件#

Inline Sprite 直接放在 HTML 或应用根组件中。优点是没有额外请求、同文档样式继承简单,currentColor 和 CSS 变量最稳定。缺点是每个 HTML 响应都带一份 sprite,图标库很大时会增加文档体积。

外部 Sprite 保存为 icons.svg,页面通过:

html已剪下 ✓
<svg class="icon" aria-hidden="true">
  <use href="/icons.svg#icon-search"></use>
</svg>

浏览器可以缓存文件,多个页面共享更合适。但跨域地址需要正确 CORS,CSP 可能限制资源,某些旧环境对外部 use 支持不足,外层 CSS 也不一定能穿透到所有内部属性。

没有绝对更好的方案。单页应用和小型图标集常用 inline;多页面站点、大型静态图标集可以测试外部文件。

viewBox 缺失时怎么办#

有些 SVG 只有 width 和 height,没有 viewBox。若尺寸是纯数字,可以临时推导为 0 0 width height。若写的是百分比、1em 或设计工具私有单位,就无法可靠推导真实坐标。

生成器会在缺少 viewBox 时给出警告,并在无法推导时暂用 0 0 24 24。这只是让预览不至于完全空白,不应该当作最终修复。应回到源文件或设计软件确认画布边界。

SVG 仍然是代码文件#

SVG 可以包含脚本、事件属性、外部图片、foreignObject 和链接。把来源不明的 SVG 直接 innerHTML 注入页面有安全风险,也可能触发外部网络请求。

生成器会移除常见危险节点、事件属性、外部 href 和明显危险 URL,但自动清理不能代替来源审查。公开项目应把图标纳入代码评审,锁定来源,并配合 CSP。

复杂插画也不适合勉强塞进 sprite。大量滤镜、内嵌位图、CSS 动画和文本可能让合并文件很重,甚至改变渲染结果。Sprite 更适合结构简单、重复使用、需要统一尺寸或颜色的界面图标。

图标的可访问性#

装饰图标可以在外层 SVG 设置 aria-hidden="true",避免屏幕阅读器重复朗读。只有图标没有文字的按钮,必须给按钮提供清楚的 aria-label

如果 SVG 本身承载独立信息,可以使用合适的 title 和 role="img",但多个 use 实例的 title 处理在不同浏览器和辅助技术中并不完全一致。界面命令优先把名称放在按钮或链接上,而不是依赖 sprite 内部 title。

一套实际制作流程#

先从设计系统导出带 viewBox 的原始 SVG,统一命名和画布尺寸。把图标批量加入生成器,处理同名文件并逐个检查预览。

单色图标开启 currentColor,多色素材保持原色。复制 inline 用法在HTML CSS JavaScript 在线预览工具中测试 hover、深色背景、不同尺寸和键盘焦点。

下载 sprite 后放到明确的静态路径,检查生产环境的缓存、CSP、跨域和实际 URL。最后在 Chrome、Safari、Firefox 与移动端抽查,不要只看本地开发服务器。

总结#

SVG Sprite 的关键不是“合成一个文件”,而是保留 viewBox、隔离内部 ID、选择正确的颜色策略、决定 inline 或外部引用,并为每个使用位置补齐可访问名称。

这些基础处理做好后,Sprite 才能真正减少重复、统一图标状态,而不是把多个独立 SVG 的问题一起打包。