SVG 优化与转换:什么时候用 SVG、PNG 还是 JPG
SVG 是一种基于文本的矢量格式,无论如何放大都不会像素化,但设计工具导出的原始 SVG 往往塞满了没用的元数据、编辑器特有属性和内联样式。清理它、去掉隐藏的攻击面,并且知道什么时候 PNG 才是更好的选择——这三件事就是让 SVG 在网页上表现出色的核心技能。
SVG 在 logo、图标、插图,以及任何必须在所有尺寸下都保持锐利的图形上都有一席之地。工作流总是那一套:从工具导出、跑 SVGO、嵌入 HTML 前做净化,只有遇到浏览器或工具链限制时才光栅化为 PNG。一个干净、优化后的 SVG 比设计工具直接吐出的文件既更小又更安全。
SVG 和 PNG、JPEG 有什么不同
SVG(可缩放矢量图形)以 XML 形式存储图形——一棵由 `<path>`、`<circle>`、`<polygon>` 等几何原语组成的树,带有填充和描边属性。因为几何是分辨率无关的,一个 SVG 从 16 像素的 favicon 缩放到广告牌尺寸都不会有任何一个像素变糊。
PNG 和 JPEG 存储的是固定网格的颜色采样。放大它们就得让渲染器在采样之间插值——这也是为什么存成 PNG 的 logo 和图标在 2× 及以上的 Retina 屏上看起来发糊,除非你提供了 2× 版本。SVG 完全绕开了这个问题。
SVG 的代价是复杂度。一张编码成 SVG、包含成千上万条渐变路径的照片,比同一张 JPEG 大得多、渲染也慢得多。图形几何简单的时候用 SVG,图像照片级复杂的时候用光栅。
为什么导出的 SVG 比它该有的体积大
Figma、Illustrator、Inkscape 这些设计工具导出的 SVG 是正确的,但并不精简。导出的文件通常包含:XML 声明、`<!DOCTYPE>` 前言、编辑器特有的命名空间(`xmlns:dc`、`xmlns:cc`、`xmlns:rdf`)、作为 `<title>` 和 `<desc>` 出现的图层名、从层叠里重复出来的内联样式、其实两位小数就够却存了六位小数的坐标,以及只包一个子元素的分组。
这些都不影响外观,但都会撑大文件。一个从 Illustrator 导出为 24 KB 的 logo,优化后常常缩到 4–6 KB,视觉上看不出差别——当这个 logo 每个页面都会加载时,这就是很可观的节省。
一条实用的 SVG 优化管线
- 从设计工具导出干净的基线
在 Figma 里用 “Copy as SVG”,或者关掉 “Include id attributes” 再导出。在 Illustrator 里用 “SVG Tiny” 或勾选 “Minify” 导出选项。在导出时减少噪音能让优化器的工作轻松很多。
- 跑 SVGO
SVGO(SVG Optimizer)是这类工作的标准命令行工具。`npx svgo --multipass input.svg -o output.svg` 会跑多轮,去除元数据、合并分组、把形状转成路径、合并冗余样式。`--multipass` 值得多花那点时间。
- 肉眼检查结果
在浏览器里打开优化后的文件,和原文件对比。SVGO 默认的预设是保守的,但像 `convertShapeToPath` 这类激进设置可能会让复杂图形的圆角或外观发生变化。在验证之前请留着原文件。
- 用 gzip 或 Brotli 发送
SVG 就是 XML,而 XML 的压缩率极高。一个已经优化到 5 KB 的 SVG,走 Brotli 常常只传 1.5 KB。设置 `Content-Type: image/svg+xml`,并确认 Web 服务器的压缩规则覆盖 `.svg`。
SVG、PNG 和 JPEG 对比
| 属性 | SVG | PNG | JPEG |
|---|---|---|---|
| 可缩放性 | 无限、无损 | 分辨率固定 | 分辨率固定 |
| 透明度 | 支持(原生) | 支持(Alpha 通道) | 不支持 |
| 最佳内容 | 图标、logo、示意图 | 截图、带透明度的图形 | 照片 |
| 照片文件体积 | 巨大(不实用) | 较大 | 较小 |
| 可作为代码编辑 | 可以 | 不行 | 不行 |
| 动画支持 | 支持(CSS/SMIL) | 仅 APNG | 不支持 |
| 浏览器支持 | 所有现代浏览器 | 全平台 | 全平台 |
什么时候把 SVG 光栅化为 PNG
有些场景无法接受 SVG:邮件客户端(多数会剥掉 SVG 或渲染错误)、Open Graph 图(社交平台要求 PNG 或 JPEG)、早于 SVG favicon 支持的 favicon 工具链,以及以位图方式导入资源的原生移动应用。
光栅化时要有意识地选目标分辨率。页面上以 200 像素宽显示的 logo,在 2× Retina 屏下至少需要 400 像素。如果这个 logo 别处还要以 600 像素宽出现,渲染成 1200 像素再让浏览器缩小——PNG 的下采样视觉效果很干净。ImageMagick 的 `magick -background none input.svg -resize 800x png:output.png` 能保留透明度并以 800 像素宽渲染。
如果想直接在浏览器里光栅化,PixMovo 支持上传 SVG 并以选定分辨率导出 PNG,很适合不想装 ImageMagick 的一次性转换。
好用的 SVGO 插件设置
- `removeViewBox: false`——保留 viewBox 属性,否则 SVG 在部分浏览器里无法正确缩放。
- `cleanupIds: true`——把冗长的 ID 重命名为短 ID;如果有 JavaScript 按名字引用了这些 ID 要谨慎。
- `mergePaths: true`——合并相邻路径,既减小文件也减少 DOM 节点。
- `convertColors: { shorthex: true }`——尽量把六位十六进制颜色转成三位。
- `removeUnknownsAndDefaults: true`——移除那些取值就是 SVG 规范默认值的属性,比如 `fill-opacity='1'`。
内联 SVG 还是 `<img src>`:怎么选
内联 SVG——直接把标签粘到 HTML 里——让你能用完整的 CSS 和 JavaScript 访问 SVG 内部元素。可以在 hover 时改变填充色、单独动画某条路径、用 querySelector 定位 ID。代价是浏览器无法把 SVG 从页面单独缓存,而且标签会撑大 HTML 文档。
用 `<img>` 或 CSS `background-image` 引入时,浏览器能独立缓存文件,HTML 也保持干净。这种模式下,JavaScript 和外部 CSS 无法伸进 SVG 内部。图标颜色要跟着主题变化时,内联 SVG 或者用 `<use>` 引用 sprite 才是对的路子。
常见问题
- 优化 SVG 用什么工具最好?
- SVGO 是标准之选。对大多数文件跑 `npx svgo --multipass input.svg -o output.svg` 即可。multipass 参数会跑多轮优化,通常能得到最小的输出。
- 在网页上使用用户上传的 SVG 安全吗?
- 不经过净化就不安全。SVG 可以包含脚本、事件处理器和外部引用,会带来 XSS 风险。上传的 SVG 在嵌入页面或存下来给其他用户查看之前,务必用 DOMPurify 或服务端净化器处理。
- 什么时候应该把 SVG 转成 PNG?
- 当目标环境不接受 SVG 时:邮件客户端、Open Graph 图、许多原生移动端资源流水线,以及任何要求特定分辨率位图的地方。为了在 Retina 屏上保持锐利,请以显示尺寸的 2× 光栅化。
- 为什么 SVGO 优化后 SVG 变糊了?
- SVGO 的激进路径合并或形状转换设置可能改动了几何。检查一下是不是 `mergePaths`、`convertShapeToPath` 或 `roundingPrecision` 造成的,然后在 SVGO 配置里把这些插件加入禁用列表。
- SVG 可以做动画吗?
- 可以。针对 SVG 元素的 CSS 动画在所有现代浏览器都能工作。SMIL 动画也被支持,但在部分引擎中已被废弃;长期来看 CSS 更稳妥。JavaScript 也可以操作 SVG DOM 元素实现交互动画。