SVG 在线压缩
SVGO 风格优化 · 去冗余 / 优化路径 / 压缩属性 · 平均减少 30-60%
SVGO 浏览器版
SVGO 风格优化 · 去冗余 / 优化路径 / 压缩属性 · 平均减少 30-60%
了解工具定位 · 使用场景 · 对比优势
用 SVGO 压缩 SVG 文件体积,移除冗余属性、空格和元数据,保留完整矢量结构。前端开发者优化图标库、设计师导出 Web 素材、运维缩小静态资源包,拖拽或选择文件即可处理。所有操作在浏览器本地完成,文件不上传服务器。
前端开发者在构建企业官网时,设计师交付的 SVG 图标集(如社交图标、导航图标)未经优化,单个文件常达 10-50KB。使用本工具批量拖入图标文件,自动移除冗余的编辑器元数据、空分组和未使用的定义,图标体积平均压缩 60%-80%,同时保留矢量清晰度,显著提升页面首屏加载速度。
移动端 H5 活动页设计师,需要将复杂的插画 SVG(含渐变、滤镜)嵌入页面,但原始文件动辄 200KB 以上。本工具在浏览器端直接处理,无需上传至服务器,通过 SVGO 算法精简路径坐标精度、合并相邻路径,将文件压缩至 30-50KB,同时确保在低端安卓机上的渲染兼容性不受影响。
产品团队在维护一套含 500+ 个 SVG 图标的组件库时,发现许多图标因多次迭代积累了冗余代码(如重复的渐变定义、空标签)。团队成员无需安装命令行工具,直接在浏览器中逐批拖入图标文件,快速清除冗余属性,使整个组件库的 SVG 总大小从 5.2MB 降至 1.8MB,大幅减少组件库的打包体积。
设计师在为客户处理含保密品牌标识的 SVG 源文件时,需要优化体积但无法将文件上传到第三方云端服务。本工具完全在浏览器本地运行,所有文件不离开用户设备,可直接拖入优化并下载压缩后的 SVG,兼顾文件瘦身需求与客户数据保密要求。
UI 设计师从 Figma 或 Sketch 导出的 SVG 图标,常包含大量设计软件特定的注释和元数据(如 sketch:type、figma-id),这些内容对网页渲染无意义但占用了文件体积。使用本工具一键清理这些冗余元数据,使导出文件体积减少 40%-70%,适合直接交付给前端开发用于生产环境。
| 维度 | 本工具 (SVGO 浏览器版) | SVGOMG (svgomg.com) | 传统方法 (手动优化) |
|---|---|---|---|
| 数据隐私 | 纯浏览器端处理,文件不上传服务器 | 纯浏览器端处理,文件不上传服务器 | 文件需交给设计师或开发人员,存在传输与泄露风险 |
| 处理速度 | 1 秒内完成,即时反馈 | 1-2 秒内完成,即时反馈 | 数分钟到数小时,取决于人工经验和文件复杂度 |
| 离线可用 | 完全离线,无需网络 | 完全离线,无需网络 | 依赖本地软件(如 Illustrator、Inkscape),无需网络 |
| 操作门槛 | 零门槛,拖拽或选择文件即可 | 低门槛,提供预设和滑块可调 | 高门槛,需掌握 SVG 结构、路径精简等专业技能 |
| 精度控制 | 提供 1-5 级预设,无法自定义参数 | 提供滑块和选项,可精细控制精度 | 完全可控,但依赖个人经验,易出错 |
| 批量处理 | 单次处理一个文件 | 单次处理一个文件 | 可批量处理,但需手动重复操作或编写脚本 |
| 收费 | 完全免费 | 完全免费 | 需支付设计师/开发人员工时费用,或购买专业软件授权 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="40" fill="red"/></svg> | <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><circle cx="50" cy="50" r="40" fill="red"/></svg> | 典型场景:简单图形,优化后几乎不变 |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2 2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg> | 典型场景:图标类 SVG,优化后移除多余空格 |
| <svg width="800" height="600" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff0000"/><stop offset="100%" stop-color="#0000ff"/></linearGradient></defs><rect width="800" height="600" fill="url(#g)"/></svg> | <svg width="800" height="600" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="g" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="red"/><stop offset="100%" stop-color="blue"/></linearGradient></defs><rect width="800" height="600" fill="url(#g)"/></svg> | 边界 case:渐变颜色名被简化为标准色名 |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="#FF0000"/><circle cx="50" cy="50" r="30" fill="#00FF00"/><circle cx="50" cy="50" r="20" fill="#0000FF"/></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red"/><circle cx="50" cy="50" r="30" fill="#0F0"/><circle cx="50" cy="50" r="20" fill="#00F"/></svg> | 边界 case:颜色值被缩短为 3 位或标准名 |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><text x="5" y="5" font-size="2" font-family="Arial">Hello World</text></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><text x="5" y="5" font-size="2" font-family="Arial">Hello World</text></svg> | 易错 case:文本内容不会被压缩,保持原样 |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><!-- 这是一个注释 --><circle cx="50" cy="50" r="40" fill="red"/></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red"/></svg> | 典型场景:注释被移除,减小文件体积 |
| <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red" fill-opacity="0.5" stroke="black" stroke-width="2"/></svg> | <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40" fill="red" opacity=".5" stroke="black" stroke-width="2"/></svg> | 边界 case:fill-opacity 被合并为 opacity |
<div><svg>...</svg></div><p>test</p><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><circle cx="50" cy="50" r="40"/></svg>SVGO 只处理纯 SVG 元素,混入 HTML 标签会导致解析失败或输出无效。输入前应只保留 <svg>...</svg> 部分。
<text>5 < 10 & 3 > 1</text><text>5 < 10 & 3 > 1</text>XML 中 <、>、& 必须转义为 <、>、&,否则解析器会误判为标签或实体开始。
<svg onload="alert(1)"><style>@import url('evil.css')</style><svg><rect width="100" height="100" fill="red"/></svg>SVGO 默认会移除 onload、onclick 等事件处理器和 @import 规则,因为优化目标是静态图形,保留这些会破坏安全性或导致优化后行为不一致。
viewBox="-99999 -99999 999999 999999"viewBox="0 0 800 600"SVGO 的坐标精度默认保留 3-5 位小数,超大 viewBox 会被截断或导致路径数据溢出。应使用合理的坐标范围。
C:\Users\me\image.svg点击“选择文件”按钮上传,或直接粘贴 SVG 文本内容浏览器端工具无法访问本地文件系统路径,必须通过 File API 读取文件内容或手动粘贴代码。
<filter id="blur"><feGaussianBlur stdDeviation="3" color-interpolation-filters="sRGB"/></filter><filter id="blur"><feGaussianBlur stdDeviation="3"/></filter>部分属性如 color-interpolation-filters 在 SVG 2 草案中已废弃,SVGO 可能保留但渲染引擎不支持。优化前应确认目标浏览器兼容性。
输入 fill="#ff0000" 期望输出 fill="red"输入 fill="#ff0000" 输出仍为 fill="#ff0000"(除非启用颜色精简插件)SVGO 默认不转换颜色表示法,因为不同工具对命名颜色的解析有差异。需要颜色精简需手动启用 colormin 插件。
<use href="https://other-domain.com/icons.svg#icon1"/><use href="#icon1"/>(前提是 #icon1 定义在同一个文件中)SVGO 不处理外部资源引用,且浏览器跨域限制会导致 <use> 无法加载外部 SVG。所有引用应内联在同一文件。
公式推导 · 流程图解 · 依据出处
size_after = size_before × (1 - reduction_rate)
size_after — 优化后的文件大小(字节)size_before — 原始文件大小(字节)reduction_rate — 压缩率(0~1,由SVGO算法决定)原始SVG文件 50KB(51,200字节),SVGO默认配置下压缩率约0.35。则 size_after = 51,200 × (1 - 0.35) = 33,280 字节 ≈ 32.5KB。实际结果因图形复杂度略有浮动。
适用于任意SVG文件(含路径、形状、文本、滤镜等元素)。不适用于已高度优化的SVG(如手动精简后的文件),此时压缩率可能低于0.05。基于SVGO v3.0+默认配置,具体压缩率受图形结构影响。
3 种主流语言 · 复制即用
// 使用 svgo 库优化 SVG(Node.js 环境)
import { optimize } from 'svgo';
const svgString = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<circle cx="50" cy="50" r="40" fill="red" />
</svg>
`;
const result = optimize(svgString, {
multipass: true, // 多次优化直到无法进一步压缩
plugins: [
'removeDoctype',
'removeXMLProcInst',
'removeComments',
'removeMetadata',
'removeEditorsNSData',
'cleanupAttrs',
'mergeStyles',
'inlineStyles',
'minifyStyles',
'removeUselessDefs',
'cleanupNumericValues',
'convertColors',
'removeUnknownsAndDefaults',
'removeNonInheritableGroupAttrs',
'removeUselessStrokeAndFill',
'removeViewBox': false, // 保留 viewBox 以保持缩放能力
'cleanupEnableBackground',
'removeHiddenElems',
'removeEmptyAttrs',
'removeEmptyContainers',
'mergePaths',
'convertShapeToPath',
'convertTransform',
'removeUnusedNS',
'sortAttrs',
'removeDimensions': true // 移除宽高,依赖 viewBox 缩放
]
});
console.log('原始大小:', svgString.length, '字节');
console.log('优化后大小:', result.data.length, '字节');
console.log('压缩率:', ((1 - result.data.length / svgString.length) * 100).toFixed(1) + '%');
console.log('优化结果:', result.data);import subprocess
import tempfile
import os
# 通过命令行调用 SVGO(需先安装:npm install -g svgo)
def optimize_svg(svg_content: str) -> str:
"""使用 SVGO 优化 SVG 字符串"""
with tempfile.NamedTemporaryFile(suffix='.svg', mode='w', delete=False) as f:
f.write(svg_content)
input_path = f.name
output_path = input_path.replace('.svg', '_min.svg')
try:
# 执行 svgo 命令,禁用移除 viewBox
result = subprocess.run(
['svgo', input_path, '-o', output_path, '--config', '{"plugins":[{"removeViewBox":false}]}'],
capture_output=True,
text=True,
timeout=30
)
if result.returncode != 0:
raise RuntimeError(f'SVGO 失败: {result.stderr}')
with open(output_path, 'r') as f:
optimized = f.read()
return optimized
finally:
# 清理临时文件
os.unlink(input_path)
if os.path.exists(output_path):
os.unlink(output_path)
# 示例
svg_input = '<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="40" fill="#ff0000"/></svg>'
optimized = optimize_svg(svg_input)
print(f'原始: {len(svg_input)} 字节')
print(f'优化: {len(optimized)} 字节')
print(f'结果: {optimized}')package main
import (
"fmt"
"os/exec"
"strings"
)
// 通过 Node.js 调用 svgo(需先安装 svgo)
func optimizeSVG(input string) (string, error) {
// 使用 Node.js 内联执行 svgo
script := fmt.Sprintf(`
const { optimize } = require('svgo');
const result = optimize(%q, {
multipass: true,
plugins: [
'removeDoctype',
'removeXMLProcInst',
'removeComments',
{ name: 'removeViewBox', active: false },
'cleanupAttrs',
'mergeStyles',
'minifyStyles',
'removeUselessDefs',
'removeUselessStrokeAndFill',
'removeEmptyAttrs',
'removeEmptyContainers',
'mergePaths',
'convertShapeToPath',
'removeUnusedNS',
{ name: 'removeDimensions', active: true }
]
});
console.log(result.data);
`, input)
cmd := exec.Command("node", "-e", script)
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("执行 SVGO 失败: %w\n输出: %s", err, output)
}
return strings.TrimSpace(string(output)), nil
}
func main() {
svg := `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100">
<rect x="10" y="10" width="80" height="80" rx="10" fill="blue" />
</svg>`
optimized, err := optimizeSVG(svg)
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Printf("原始大小: %d 字节\n", len(svg))
fmt.Printf("优化后大小: %d 字节\n", len(optimized))
fmt.Printf("压缩率: %.1f%%\n", (1-float64(len(optimized))/float64(len(svg)))*100)
fmt.Println("优化结果:")
fmt.Println(optimized)
}8 个高频疑问
「格式转换」下的其他工具