SVGO 压缩 SVG 后不能正常缩放

前情提要

在前端开发过程中,SVG 图标(可缩放矢量图形)被广泛使用,因为它们具有可伸缩性、清晰的显示效果以及较小的文件大小。使用 SVG 作为图标有很多优势,尤其是在响应式设计和高分辨率屏幕上的表现。

但是,SVG 图标的制作过程也有很多不便之处。一千个读者就有一千个哈姆雷特,一千个制作者绘制同一个图标也可能会有一千个不同的版本。尽管 SVG 本身已经足够小了,但是在很多矢量编辑器/软件中,导出来的 SVG 文件会有很多其他冗余信息(当然这里面制作者和导出软件可能都会有问题)。

为了解决这些问题,我们需要一个工具来压缩 SVG 图标,使其更小、更清晰、更易于管理。所以选择了 SVGO 对图片进行压缩并且使用 SVGR 将 SVG 代码转换为 React Component 。

你可以在这尝试进行 svg 的压缩与转化。

ps: scgr 会默认使用 svgo 帮你压缩 svg 代码。

npx @svgr/cli --typescript --out-dir ./svgicons -- svgrz

压缩效果也是显著:
svgo-1.png

但是在使用的时候发现了一个问题,有一部分压缩完的 SVG 不能设置宽高,如果设置了宽高,会导致 svg 只有一部分展示。

问题原因

检查 SVG 代码发现,viewBox 标签不见了。删除掉 viewBox 会导致 SVG 不能正常缩放。可以说这属于是破环性的压缩,很难理解 svgo 为了 “minimizing number of bytes” 而删除 viewBox 标签。

svgo-2.png

svgo-3.png

因为对于 SVG 规范了解的并不够深入,所以不能确定 svgo 压缩是否是正确的,查看 issues 发现很多前端开发都提出了这个问题,但 svgo 似乎并不像修改。

解决方案

为了解决这个问题,在压缩 SVG 代码时,我们需要通过配置文件来保留 viewBox 标签。

添加 svgo.config.js 文件

export default {
  plugins: [
    {
      name: "preset-default",
      params: { overrides: { removeViewBox: false } },
    },
  ],
};

因为 SVGR 会默认使用 SVGO 进行压缩,所以我们需要使用 --no-svgo 禁止 SVGR 的压缩操作

svgo -f svg/ -o svgrz/ && npx @svgr/cli --typescript --out-dir ./svgicons --no-svgo -- svgrz

到这里,SVG 图标的压缩与转化就完成了。

参考资料

更多关于 SVGO 压缩 viewBox 标签的讨论:
issue 1461
issue 1128

svgo-4.png