为什么 SVG 需要优化
SVG(Scalable Vector Graphics)作为矢量图形格式,天然适合 Web 场景:无限缩放、可被 CSS 控制、可被 JavaScript 操作、SEO 友好。但编辑器(Inkscape / Illustrator / Sketch / Figma)导出的 SVG 通常含大量冗余信息,体积往往是必要体积的 2-5 倍。
编辑器导出 SVG 的典型问题
一个 Inkscape 导出的简单图标 SVG 可能长这样:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
viewBox="0 0 100 100"
id="Layer_1"
inkscape:version="1.0"
sodipodi:docname="icon.svg">
<metadata id="metadata8">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
</cc:Work>
</rdf:RDF>
</metadata>
<circle cx="50.00000" cy="50.00000" r="40.00000"
fill="black" stroke="none" stroke-width="1"
inkscape:label="背景圆" />
</svg>
冗余信息包括:
| 类型 | 示例 | 占用体积 | 必要性 |
|---|---|---|---|
| XML 声明 | <?xml version="1.0"?> | ~50 B | HTML 内联不必要 |
| 编辑器注释 | <!-- Created with Inkscape --> | ~40 B | 不必要 |
| metadata 元素 | RDF 版权信息 | ~300 B | 不影响渲染 |
| 编辑器命名空间声明 | xmlns:sodipodi xmlns:inkscape | ~200 B | 不影响渲染 |
| 编辑器属性 | inkscape:label sodipodi:docname | ~50 B/个 | 不影响渲染 |
| 无意义 id | Layer_1 | ~15 B/个 | 不影响渲染(未被引用时) |
| 多余精度 | 50.00000 | 5 B/个 | 可简化为 50 |
| 默认值属性 | fill="black" stroke="none" | ~25 B/个 | SVG 默认值 |
| 换行缩进 | 编辑器为可读性添加 | 体积的 10-20% | 对渲染无影响 |
优化的收益
典型 Inkscape 导出 SVG 经完整优化可压缩 30%-60%:
- 首屏 LCP 改善:每 KB 都影响移动端首屏加载
- HTML 体积减小:内联 SVG 直接增加 HTML 字节数
- CDN 流量节省:高流量站点累计节省可观
- 代码可维护性:去除编辑器残留后 SVG 结构清晰
编辑器残留的常见类型
Inkscape 残留
Inkscape 是开源 SVG 编辑器,导出 SVG 含大量编辑器元数据:
<!-- Inkscape 命名空间声明 -->
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
<!-- Inkscape 属性 -->
inkscape:version="1.0"
inkscape:label="背景圆"
sodipodi:docname="icon.svg"
sodipodi:nodetypes="cccc"
<!-- Inkscape id 模式 -->
id="Layer_1"
id="path1234"
Adobe Illustrator 残留
Illustrator 导出 SVG 时会编码特殊字符为 _xHH_ 格式:
<!-- Adobe id 编码:_x2C_ = 逗号,_x3C_ = 小于号 -->
id="_x2C__x3C_icon_x3E_"
<!-- Adobe 命名空间 -->
xmlns:i="http://ns.adobe.com/AdobeIllustrator/10.0/"
xmlns:graph="http://ns.adobe.com/Graphs/1.0/"
Sketch 残留
Sketch 导出 SVG 时含 sketch 命名空间:
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
sketch:type="MSShapeGroup"
Figma 残留
Figma 导出相对干净,但仍可能含编辑器 id:
id="Rectangle-1"
id="Path-2"
优化规则分类与原理
本站 SVG 优化器将 11 条规则按作用层次分为 4 类:
1. 结构清理类(4 条)
| 规则 | 作用 | 安全性 |
|---|---|---|
removeXmlDecl | 去除 <?xml ... ?> 声明 | HTML 内联安全;独立文件场景浏览器不依赖此声明 |
removeDoctype | 去除 <!DOCTYPE ... > 声明 | 安全(DOCTYPE 在 SVG 中仅用于实体声明,现代浏览器不依赖) |
removeComments | 去除 <!-- --> 注释 | 安全(注释不影响渲染) |
removeMetadata | 去除 <metadata> 元素 | 安全(metadata 不参与渲染,仅含版权与编辑器元数据) |
2. 元素清理类(2 条)
| 规则 | 作用 | 安全性 |
|---|---|---|
removeDesc | 去除 <desc> 描述元素 | 安全(desc 不参与渲染,仅辅助描述) |
removeTitle | 去除 <title> 元素 | 影响无障碍,默认关闭;内联场景可开启 |
3. 属性清理类(2 条)
| 规则 | 作用 | 安全性 |
|---|---|---|
removeEditorAttrs | 去除编辑器命名空间属性 | 安全(编辑器属性不参与 SVG 渲染) |
removeEditorIds | 去除编辑器自动生成的无意义 id | 条件安全(仅移除未被 url(#id) href="#id" 引用的 id) |
4. 数值与文本优化类(3 条)
| 规则 | 作用 | 安全性 |
|---|---|---|
shortenNumbers | 数字精度简化(0.5 → .5、1.000 → 1) | 安全(SVG 规范允许) |
removeDefaultAttrs | 去除默认值属性(fill="black") | 安全(属性值为 SVG 默认值时移除) |
collapseWhitespace | 压缩空白与换行 | 条件安全(保护 <text> <tspan> 内容) |
数字精度简化的安全性
shortenNumbers 规则常被误解为可能破坏渲染,实际上是 SVG 规范明确允许的安全优化。
SVG 规范允许的数字格式
SVG 属性值中的数字遵循 XML Number 规范,以下写法完全等价:
<!-- 全部等价 -->
<circle cx="50" />
<circle cx="50.0" />
<circle cx="50.00000" />
前导零省略
SVG 规范允许省略小数点前的 0:
<!-- 全部等价 -->
<circle r="0.5" />
<circle r=".5" />
本工具的简化规则:
// 匹配属性值中的浮点数(不含颜色 hex)
s.replace(/(?<=[=(",\s])-?\d+\.\d+/g, (match) => {
const num = parseFloat(match);
const fixed = num.toFixed(3).replace(/\.?0+$/, ''); // 保留 3 位小数 + 去尾随零
return fixed.replace(/^(-?)0\./, '$1.'); // 去前导零
});
精度截断的影响
保留 3 位小数对屏幕渲染几乎无影响:
- 屏幕 DPI 通常 96-192,1px = 1/96 inch
- 3 位小数精度 = 0.001px,远小于亚像素渲染阈值
- 仅在像素级精确的印刷场景(300+ DPI PDF 矢量图)可能可见差异
不处理颜色 hex
#3b82f6 不含小数点,不会被 shortenNumbers 匹配,颜色值保持原样。
默认值属性的处理
removeDefaultAttrs 规则移除属性值等于 SVG 默认值的属性,减少冗余声明。
SVG 常见默认值
| 属性 | 默认值 | 说明 |
|---|---|---|
fill | black | 默认填充黑色 |
fill-opacity | 1 | 默认完全不透明 |
fill-rule | nonzero | 默认非零环绕规则 |
stroke | none | 默认无描边 |
stroke-width | 1 | 默认描边宽度 1 |
stroke-linecap | butt | 默认平头线帽 |
stroke-linejoin | miter | 默认尖角连接 |
stroke-opacity | 1 | 默认描边完全不透明 |
opacity | 1 | 默认元素完全不透明 |
text-anchor | start | 默认文本左对齐 |
dominant-baseline | auto | 默认基线自动 |
移除的注意事项
仅移除精确匹配默认值的属性:
<!-- 会被移除 -->
<circle fill="black" /> <!-- fill 默认 black -->
<rect stroke="none" /> <!-- stroke 默认 none -->
<!-- 不会被移除 -->
<circle fill="#000000" /> <!-- hex 值,非 "black" 关键字 -->
<rect stroke="rgba(0,0,0,0)" /> <!-- rgba 值,非 "none" -->
继承的影响
SVG 属性支持继承,父元素的 fill="black" 会影响子元素。但若子元素未显式设置 fill,父元素的 fill="black" 等同于默认值,移除后子元素仍继承默认的 black,渲染结果不变。
例外场景:若父元素显式设置 fill="red",子元素设置 fill="black" 覆盖父值,此时子元素的 fill="black" 不能被移除(否则会继承父元素的 red)。本工具的简单字符串匹配无法识别继承关系,因此 removeDefaultAttrs 在复杂继承场景需谨慎使用。
内联 SVG 的最佳实践
SVG 内联到 HTML / CSS 是现代 Web 开发的常见模式,可减少 HTTP 请求、支持 CSS 控制、增强交互能力。
内联方式对比
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 直接嵌入 HTML | CSS 可控、支持交互 | 增加 HTML 体积 | 图标系统、装饰图形 |
<use> 引用 | 复用、缓存 | 需 SVG sprite 定义 | 图标库(如 FontAwesome) |
| data URI | 可用于 CSS background | 需 URL 编码 | 装饰背景、<img src> |
外部 <img> | 浏览器缓存 | 无法 CSS 控制内部 | 独立图片资源 |
内联优化建议
<!-- 优化前:Inkscape 导出原始 SVG -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black">
<title>保存图标</title>
<path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
</svg>
<!-- 优化后:内联到 HTML,使用 currentColor 便于主题切换 -->
<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
<path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/>
</svg>
内联优化要点:
- 移除
xmlns命名空间声明(HTML 内联不需要) - 使用「激进」预设移除 title 与 desc(避免屏幕阅读器重复读出)
- 保留
viewBox(CSS 控制尺寸的核心) - 使用
fill="currentColor"便于 CSS 控制颜色(color: red即可改图标颜色) - 添加
aria-hidden="true"隐藏装饰图标(父元素提供aria-label)
data URI 编码
CSS background-image 使用 SVG 需 URL 编码:
/* 优化前:直接嵌入会因 # 等字符破坏 CSS 语法 */
.icon {
background-image: url('data:image/svg+xml,<svg viewBox="0 0 24 24"><path d="..." fill="#3b82f6"/></svg>');
}
/* 优化后:URL 编码 # 与特殊字符 */
.icon {
background-image: url('data:image/svg+xml,%3Csvg viewBox="0 0 24 24"%3E%3Cpath d="..." fill="%233b82f6"/%3E%3C/svg%3E');
}
可配合本站 Base64 工具进一步编码为 data:image/svg+xml;base64,... 格式。
与 SVGO 的对比与差异
SVGO 是 Node.js 生态最成熟的 SVG 优化工具,本工具与 SVGO 的定位差异:
| 维度 | 本工具 | SVGO |
|---|---|---|
| 运行环境 | 浏览器纯本地 | Node.js CLI / 构建工具集成 |
| 实现方式 | 字符串与正则 | AST 解析(基于 sax) |
| 优化规则数 | 11 条 | 30+ 插件 |
| path 数据优化 | 不支持 | 支持(convertPathData) |
| 形状转换 | 不支持 | 支持(convertShapeToPath、convertEllipseToCircle) |
| 实时预览 | 支持 | 不支持 |
| 部署方式 | 在线工具 | 本地工具链 |
本工具不实现的 SVGO 插件
| SVGO 插件 | 不实现原因 |
|---|---|
convertPathData | path 坐标相对化与指令合并复杂度高,且易引入渲染差异 |
convertShapeToPath | 形状转 path 不可逆,需语义分析 |
mergePaths | path 合并需判断可合并性,复杂度高 |
convertTransform | transform 矩阵化需数学计算,且可能改变语义 |
removeUselessDefs | 需 AST 分析引用关系,正则实现易误删 |
协同工作流
推荐工作流:开发期用 SVGO 在构建时深度优化(path 数据等),临时场景用本工具快速优化。
- 开发期:在 webpack / Vite 集成
svgo-loader或vite-plugin-svgo,构建时自动优化 - 运行时:用户上传 SVG 时用本工具快速优化(无后端依赖)
- 调试期:用本工具的「预览对比」与「规则统计」逐条验证规则效果
保守 / 标准 / 激进 3 套预设选型
本工具内置 3 套预设,对应不同场景:
保守预设
{
removeXmlDecl: true,
removeDoctype: true,
removeComments: true,
removeMetadata: true,
removeDesc: false, // 保留 desc
removeTitle: false, // 保留 title
removeEditorAttrs: true,
removeEditorIds: true,
shortenNumbers: false, // 保留原始精度
removeDefaultAttrs: false, // 保留默认值属性
collapseWhitespace: false, // 保留可读性
}
适用场景:印刷级 SVG、需要保留可读性与调试信息的场景、高精度矢量图。 典型压缩率:10%-20%。
标准预设(默认)
{
removeXmlDecl: true,
removeDoctype: true,
removeComments: true,
removeMetadata: true,
removeDesc: true,
removeTitle: false,
removeEditorAttrs: true,
removeEditorIds: true,
shortenNumbers: true,
removeDefaultAttrs: true,
collapseWhitespace: true,
}
适用场景:大多数 Web 场景、网站 logo、导航图标、内容配图。 典型压缩率:30%-50%。
激进预设
{
...标准预设,
removeTitle: true, // 移除 title(影响无障碍)
}
适用场景:SVG 内联到 HTML / CSS、装饰性图标(父元素提供 aria-label)、favicon。
典型压缩率:40%-60%。
最佳实践与总结
SVG 优化最佳实践
- 优先用标准预设:覆盖 90% 场景,平衡体积与可读性
- 内联场景切激进:HTML 内联 SVG 不需要 title 与 xmlns
- 保留
viewBox:CSS 控制尺寸的核心属性,不可移除 - 使用
currentColor:图标颜色由 CSS 控制,便于主题切换 - 验证渲染:用本工具的「预览对比」逐个验证优化后的 SVG
- 开发期集成 SVGO:构建时深度优化 path 数据,运行时无需重复优化
- 图标系统用
<use>:复用率高时用 SVG sprite +<use href="#id">引用
日常优化清单
- 是否去除 XML 声明与 DOCTYPE
- 是否去除编辑器命名空间与无意义 id
- 是否简化数字精度
- 是否去除默认值属性
- 是否压缩空白与换行
- 是否保留
viewBox与必要id - 是否验证预览渲染一致
- 内联场景是否移除
xmlns与title
与本站工具矩阵协同
| 场景 | 推荐工具 |
|---|---|
| SVG 文本优化 | 本工具(/svg-optimizer) |
| 位图压缩(PNG/JPEG/WebP) | 图片压缩(/image-compress) |
| 图片元数据查看 | EXIF 查看(/exif) |
| SVG 转 data URI 内联 | Base64 图片互转(/base64-image) |
| 图标颜色调整 | 颜色转换(/color) |
| 二维码生成 | 二维码生成(/qr) |
| CSS 代码压缩 | CSS 格式化(/css-formatter) |
总结
SVG 优化是 Web 性优化的低成本高收益环节,本工具基于字符串与正则的轻量方案覆盖 80% 通用场景:
- 11 条规则独立开关,可逐条验证效果
- 3 套预设覆盖保守 / 标准 / 激进三类场景
- 实时预览对比确保优化不破坏渲染
- 纯本地处理保护敏感图标隐私
对于 path 数据级深度优化,建议在构建工具链集成 SVGO;对于运行时与临时优化场景,本工具提供零依赖的快速方案。两者协同可覆盖 SVG 优化的完整工作流。