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 优化管线

  1. 从设计工具导出干净的基线

    在 Figma 里用 “Copy as SVG”,或者关掉 “Include id attributes” 再导出。在 Illustrator 里用 “SVG Tiny” 或勾选 “Minify” 导出选项。在导出时减少噪音能让优化器的工作轻松很多。

  2. 跑 SVGO

    SVGO(SVG Optimizer)是这类工作的标准命令行工具。`npx svgo --multipass input.svg -o output.svg` 会跑多轮,去除元数据、合并分组、把形状转成路径、合并冗余样式。`--multipass` 值得多花那点时间。

  3. 肉眼检查结果

    在浏览器里打开优化后的文件,和原文件对比。SVGO 默认的预设是保守的,但像 `convertShapeToPath` 这类激进设置可能会让复杂图形的圆角或外观发生变化。在验证之前请留着原文件。

  4. 用 gzip 或 Brotli 发送

    SVG 就是 XML,而 XML 的压缩率极高。一个已经优化到 5 KB 的 SVG,走 Brotli 常常只传 1.5 KB。设置 `Content-Type: image/svg+xml`,并确认 Web 服务器的压缩规则覆盖 `.svg`。

SVG、PNG 和 JPEG 对比

属性SVGPNGJPEG
可缩放性无限、无损分辨率固定分辨率固定
透明度支持(原生)支持(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 还是 `&lt;img src&gt;`:怎么选

内联 SVG——直接把标签粘到 HTML 里——让你能用完整的 CSS 和 JavaScript 访问 SVG 内部元素。可以在 hover 时改变填充色、单独动画某条路径、用 querySelector 定位 ID。代价是浏览器无法把 SVG 从页面单独缓存,而且标签会撑大 HTML 文档。

用 `&lt;img&gt;` 或 CSS `background-image` 引入时,浏览器能独立缓存文件,HTML 也保持干净。这种模式下,JavaScript 和外部 CSS 无法伸进 SVG 内部。图标颜色要跟着主题变化时,内联 SVG 或者用 `&lt;use&gt;` 引用 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 元素实现交互动画。

官方来源