理解并手动改进 SVG 优化

Avatar of Raymond Schwartz
Raymond Schwartz

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 $200 免费信用额度!

以下是 Raymond Schwartz 的客座文章。 与其栅格兄弟姐妹一样,SVG 应该在用于生产网站之前进行优化。 有很多很棒的工具可以做到这一点,但正如 Raymond 即将向您展示的那样,最好的结果来自更深入的理解和一些手动操作。 例如,小数精度是 SVG 优化的一个重要因素,但它是一个相当武断的指标,取决于 SVG 的坐标系。 改变该系统,获得不同的结果。 以下是 Raymond 的见解。

三个因素决定了 SVG 的优化文件大小:物理尺寸、viewBox 和小数精度。 武断地设置其中任何一个都会让您损失宝贵的字节,甚至是千字节。 每个 SVG 都具有这三个属性的特定组合,这将产生最小的文件大小。 通过了解每个属性如何影响矢量路径的表达,您可以发现如何调整它们以实现最佳优化。

1) 物理尺寸:揭穿 SVG 中的“可缩放性”(某种程度上)

要创建 SVG,请启动您最喜欢的矢量图形编辑器,设置文档,并制作一些视觉上引人入胜的东西。 文档设置的一部分是定义物理尺寸。 这可能看起来并不重要,因为根据定义,矢量图形是可缩放的,视觉尺寸将根据其上下文而变化。 虽然这对于视觉表示是正确的,但对于代码表示则不正确,代码表示保持不变。 代码表示部分源自容器的尺寸(或 Illustrator 中的“画板”),该尺寸由离散的度量值描述。 通过设置尺寸,您已经部分决定了文件大小。

2) viewBox 和微优化

尺寸除了指导路径表达之外,还决定了 viewBox 属性的值。

viewBox 可能看起来像这样

viewBox="-351.7474061, 2051.85204372, 2520.3925946, 2520.13473217"

考虑到我们可以以无损的方式进行微优化,这太长了,而不会在视觉上改变图像。 首先,将左上角设置为 0,0

viewBox="0, 0, 2872.1400007, 468.28268845"

这节省了 23 个字节,因为一个字符等于一个字节。 接下来,将宽度和高度四舍五入为整数,如果需要,缩放图稿

viewBox="0, 0, 2872, 468"

这又节省了 17 个字节。 最后,将画板缩小以减少位数

viewBox="0, 0, 252, 252"

再加两个,总共节省了 42 个字节。 即使节省的字节很少,这种优化也很容易执行,而且没有任何负面影响。 现在您已经知道,您将从一开始就以这种方式设置文件,这应该内置到您的文件设置中。 但更重要的是,正如我们将看到的那样,这种方法对路径中节省字节的影响要大得多。

3) 小数精度:哪个最好?

当您保存 SVG 时,您需要指定一个小数精度,通常是一个介于 1 到 8 之间的整数。 它定义了所有数值小数点后的位数。 请记住,字符等于字节,我们拥有的字符越少,文件就越小。 随着小数精度的降低,字节数也会减少,每个数字可能减少 7 个字节。

但随着精度的降低,SVG 可能会在视觉上出现问题,因为可能没有足够的数据来准确地描述它们。 随着精度的提高,会存在更多细节,但在某个点之后,可能不会提高保真度,从而浪费字节。 我们的目标是在文件大小和视觉保真度之间取得平衡,并准确地知道平衡点在哪里。

此设置没有解决的是小数点左侧有多少个有效数字。 这就是调整尺寸和 viewBox 发挥作用的地方。 接下来,我们将检查路径(定义绘图的内容)以及尺寸、viewBox 和小数精度如何影响它们包含的字符数。


路径是什么样子的?

我们的示例基于 Chris Coyier 的使用 SVG 中的奇异鸟,有两个路径:一个是椭圆,另一个是奇异鸟。 它的尺寸为 100px 宽度 x 82px 高度,viewBox 为 0 0 100 82,小数精度为 7,这是 Illustrator 允许的最高精度。

来自 Chris Coyier 的使用 SVG 的奇异鸟 SVG 的视觉表示。

基本形状有自己的标签:circleellipselinepolygonpolylinerect。 由于这些形状定义明确,因此描述它们所需的代码量最少,您只需要一些属性/值对即可。 以下是示例中椭圆的代码

<ellipse fill="#C6C6C6" cx="46.3267326" cy="68.9376144" rx="42.3298607" ry="13.0623865"/>

要描述除基本形状以外的任何形状,都需要 path 标签。 以下是奇异鸟的路径,包括第一部分和最后一个值

<path id="bird" d="M34.363224,0.0008523C17.0553761,0.1314738-2.0175736,13.9286251,0.1724619,34.4692345c0.7027745,6.5964966,3.0235648,10.4009247,8.5313501,12.8991089c5.9327183,2.6941185,9.315836,8.915081,8.2371655,18.4506187 … 72.8360062,22.4844837z"/>

整个值大约长 20 倍。 对于如此多的字符,非标准形状提供了最大的优化机会。 请注意,所有数字都具有 7 位小数精度。 优化工具无法添加细节,因此如果您以较低精度保存,就会限制您的选择。 始终以编辑器允许的最高小数精度保存。

尺寸和小数精度如何影响路径

奇异鸟路径中的第一个值为:M34.363224,0.0008523

这定义了路径的起点。 M 表示移动到某个位置。 用逗号分隔的数字分别是该位置的 x 和 y 坐标。 它们源自左上角的坐标(viewBox)、您的尺寸比例以及您选择的小数精度。

从我们的示例文件中,我通过将宽度和高度乘以 10 和除以 10 创建了另外四个文件。 以下是每个文件中的奇异鸟路径的第一个值和最后一个值

尺寸 第一个值 最后一个值
1×1 M0.3436333,0.0000095 0.7283611,0.2248458z
10×8.2 M3.4363234,0.0000861 7.2836018,2.2484493z
100×82 M34.363224,0.0008523 72.8360062,22.4844837z
1,000×820 M343.6322327,0.0085142 728.3600464,224.8448334z
10,000×8,200 M3436.3222656,0.0851329 7283.6005859,2248.4482422z

具有 7 位小数精度时,坐标长度的下限为 9 个字符,即小数点、前导零和 7 个小数,或者最多比小数精度多 2 个字符。 如果您的坐标是 0.1479000,则长度可能会更短,例如,它将减少为 0.1479,但非标准形状的性质使得出现此类值非常不可能。

坐标长度的上限仅受编辑器画板大小的限制。 请注意,每次尺寸乘以 10 时,每个坐标的小数点左侧都会增加一个有效数字。 请记住,更多的字符意味着更大的文件大小。

尺寸如何影响文件大小?

请查看我们五个文件在使用 SVGO-GUISVGO 的一个端口,但具有拖放式 GUI 界面)进行优化时的效果。 虽然拖放很方便,但这方便是有代价的。 SVGO-GUI 仅使用 3 位小数精度进行优化。 然而,这对于仅演示尺寸的影响是完美的。 以下是结果

从该表中可以看出,随着尺寸的减小,利润(文件减少的百分比)会增加,也就是说,尺寸越小,优化器能够使您的文件越小。 还要注意,文件大小在优化之前也会减小。

我使用 SVGO-GUI 来说明一个观点。 它非常适合批量优化,超级方便,而且如果您没有太多时间,它也非常适合您。 但是,如果您想获得最小的文件,则需要使用低于 3 位的小数精度,这意味着我们必须使用其他工具。

找到尺寸和小数精度的最佳组合

从 SVGO-GUI 的反馈来看,从 kiwi-10 到 kiwi-1,"之后" 文件大小下降了惊人的 50%。虽然在纸面上看起来很好,但在屏幕上看起来并不好。在下一张图中,左边是 kiwi-10,看起来像原始图像。中间是 kiwi-1,你可以看到整体细节损失。右边是 kiwi-10,其小数精度从 3 降至 1,同样不可用。

从左到右:kiwi-10、kiwi-10 降低维度和 kiwi-10 降低小数精度。

随着维度的降低,路径包含的细节也会降低。想象一下 5.5555555 的坐标。每次维度降低 10 倍时,就会失去最后一位数字 - 0.5555555、0.0555555、0.0055555 等等。在某个时刻,会失去太多细节,以至于 SVG 在视觉上会断裂。类似地,SVG 也会随着小数精度的降低而断裂 - 尽管以不同的方式。我们的挑战是找到维数和小数精度之间的完美组合,既能保持视觉保真度,又能产生最少的字符数量。

为此,我们将从基于 kiwi 创建一系列文件开始,其尺寸基于 2 的幂 - 1、2、4、8 等等。我在 Illustrator 中发现的最简单方法是选择所有图稿,将其复制到剪贴板,创建一个新文档,设置尺寸,然后粘贴。在打开变换调色板并选中所有路径的情况下,将 x 和 y 坐标设置为 0,并将宽度或高度中的较大者设置为画板的相应尺寸。确保选中变换调色板的链接图标以保持纵横比。继续执行此操作,直到达到 1024px 或 2048px。

现在,是时候使用 Jake Archibald 的在线优化器 SVGOMG! 了。这是一个功能强大且全面的优化器,可以在线和离线使用。虽然 SVGOMG! 具有内置缩放功能,但在较小的尺寸下,您需要将宽度属性编辑为合理的值才能清楚地看到图像(500px 就足够了)。打开第一张图像(1×1)。确保 "Compare gzipped"、"Prettifycode" 和 "Multipass" 已关闭。切换 "Show original" 以比较未优化的图像和优化的图像。我们将从调整小数精度开始,逐步找到最佳文件。找到您在视觉断裂发生之前可以接受的最低小数精度,并将其记录下来。以下是针对每张图像执行此操作后的结果:

尺寸
(像素单位的正方形)
最低小数精度
无断裂
优化后的文件大小
(K)
1 4 1.4
2 3 1.25
4 3 1.28
8 3 1.29
16 3 1.31
32 3 1.39
64 2 1.22
128 2 1.34
256 1 1.11
512 1 1.18
1024 1 1.28

我们已经讨论过这张图表中的一些模式 - 在较小的尺寸下,需要更高的小数精度才能避免视觉断裂;在较大的尺寸下,可以接受较低的小数精度;尺寸越大,文件大小越大。

出现了一种新模式 - 小数精度为 1 将产生最小的文件。在每次“跳跃”到下一个较低的小数精度时,文件大小都会明显减小。小数精度为 4 时,最小文件为 1.4k;小数精度为 3 时,最小文件为 1.25k;小数精度为 2 时,最小文件为 1.22k;小数精度为 1 时,最小文件为 1.11k。仍然未知的是,小数精度为 1 不会断裂的最小尺寸。

请注意,我们目标变化的范围几乎为 0.3k,超过最高值的 20%。如果我们没有选择特定的值,范围会更大。这使您了解任意决策对文件大小的影响程度。

为了精确地找到产生最小文件大小的尺寸/小数精度组合,请关注小数精度中的跳跃。我们可以消除两次跳跃 - 从 4 到 3,以及从 3 到 2 - 因为存在更小的文件大小(从 2 到 1 的跳跃),并且这些跳跃内的任何点都将更大。这仅剩第一次从 2 到 1 的跳跃需要检查。

创建一个宽度为第一次跳跃中点 - 192 的文件。在小数精度为 1 时,它为 1.06k 并且看起来可以接受。请记住,这些差异几乎无法察觉,只有在 SVGOMG! 中切换原始视图和优化视图时才能看到。下一个中点 - 128 和 192 之间 - 是 160。这个看起来不好,并且略微上升到 1.07k - 文件大小可能会停滞,与已建立的模式相反。为了检查,我查看了 200,它为 1.08k - 正如预期的那样,再次上升。190 和 194 都为 1.07k。因此,最佳尺寸是在宽度为 192px 且小数精度为 1 时实现的。我们竟然知道这一点,太神奇了!

更多微优化

以下是 SVGOMG! 对我们获胜者 192×192 优化的代码

<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192"><ellipse cx="88.9" cy="132.4" fill="#C6C6C6" rx="81.3" ry="25.1"/><path d="M66 0C32.7.3-4 26.7.3 66.2 1.7 78.8 6 86.2 16.7 91c11.4 5 18 17 15.8 35.4-3 1.5-5.4 3.4-6 6.2 2.4 0 4.7 0 7 1.4 6.5 4 10 8.6 13.6 16.2.7 1 2.7 1 2.7-1 0-2.6-.6-5.5-1.6-8.4-1-2.6 1-2.5 2.3-2 2 1 5 3 9.5 4.2 1.7.4 2-1.2 1.6-2.2-.6-2.4-3.4-3.4-7.7-6-1.5-1-.2-3 1.7-2.7l6.3 1c1 0 1.5-2 .3-2.6-4.5-2-9-3-17-2.4-3.6-9.2-9.3-19.3-4.8-25.6 4-5.6 9.7-6.5 12.2 13.6-1.5 1-3.5 1.6-3.5 4 2-.8 3.4-.4 4.5 0 5.6 2.3 11.2 7 16.7 11.8 1 1 2.6-.6 2-2-.5-2-2.4-3.3-4.5-6.2-1-1.4 1.6-2.2 3.4-2 4.5 0 7.3 2.5 11.2 3.4 1.4.3 3-.7 2-2.2-1-2-4-2.8-6-4.2-1.3-1-.8-2.2 1-2 1.2 0 2.6.7 4.3.5 3-.2 2.4-2.2-.3-3-6-1.6-12.5-2-19.3-1.5-14-2.7-10-26.7 0-28.4C73 82.6 83.5 80 95 74c10.3-1.7 20.4-4 29.2-10.6 15-4.5 35 5 64 47 1.3 1.7 5 3 3-2-5-13-21.4-29.3-29-41.5C155 54.4 158 47.6 150 38.2c-6.7-7.8-15-8-24.3-5.4-7.3 2-12.3-2.3-16.6-10C100 7 83.5 0 66 0zm73.8 43.2c2 0 3.5 1.5 3.5 3.4 0 2-1.5 3.5-3.5 3.5s-3.4-1.5-3.4-3.4c0-2 1.5-3.4 3.4-3.4z"/></svg>

SVGOMG! 在优化路径和移除编辑器注入的垃圾方面做得非常出色。它还会告诉您原始文件的大小 - 在这种情况下,为 3.92k,而优化后的文件大小为 1.06k,节省了 72.96%!在剩下的部分中,还有更多优化机会可以利用。

如果您只支持符合 HTML5 的浏览器,可以安全地移除 xmlns 属性。在 HTML 文档的上下文中,xmlns 对于 SVG 元素是隐含的。为了向后兼容 XHTML 或将您的标记视为有效的 XML,请保留它。如果移除,则可以节省 35 字节。

如果您的图像可以进行视觉编辑,将椭圆的所有属性值四舍五入到最接近的整数将移除更多字节,但会略微改变其位置。将颜色更改为类似但重复的颜色,例如 #ccc,可以将该值减半。您也可以使用 CSS 针对 SVG 的容器元素,并完全移除此属性。这些微优化可以节省 23 字节,总共可以节省 58 字节,最终文件大小为 1.025k - 节省了 73.85%。

移除宽度和高度属性将进一步优化我们的文件。尤其是在响应式上下文中,为什么要以像素为单位显式设置宽度和高度?响应式 SVG 是通过 CSS 实现的,CSS 会覆盖宽度和高度属性。但是,保留它们的优势超过了移除它们可能带来的任何优化优势。但是,如果仍然希望保持流畅性,它们可能会保留下来。

为什么宽度和高度属性应该保留

如果您遵循渐进增强原则,则需要在没有 CSS 的情况下测试您的页面。CSS 使 SVG 成为响应式,并且不再适用。没有宽度和高度属性的 SVG 在没有 CSS 的情况下渲染时会发生什么?它会填充整个视窗的宽度。这可能不是您想要的,并且会导致难以阅读和看起来损坏的页面。

下一张图显示了没有技巧的 CSS-Tricks。标题栏在整个宽度上看起来都很好,因此保留了宽度和高度属性,但搜索图标则没有。它将搜索标签与搜索框分隔开来,视觉上过于突出,并导致过度垂直滚动。

以下是将值为 16 的宽度属性添加到搜索图标时会发生的情况

这更符合应用了 CSS 后图标的外观,使页面更易读,并重新建立适当的视觉层次结构。

注意填充方式

从另一个角度来看,这是页面顶部在中等媒体查询中应用 CSS 后看起来的样子。

请注意,"CSS-TRICKS" 和 "treehouse" SVG 都是黑色背景上的白色,但在上图中,"CSS-TRICKS" 变为黑色,而 "treehouse" 保持白色 - 因此在白色背景下不可见。可以通过 CSS 或 fill 属性添加颜色。在 Treehouse 徽标的情况下(很可能是 Treehouse 提供的),使用了 fill 属性来添加填充颜色。当 CSS 缺失时,fill 属性仍然适用,因此 Treehouse 徽标仍然是白色的。

将演示文稿置于 CSS 而不是由属性控制,可能更安全、更直观。如果样式需要与 SVG 打包在一起,请使用样式属性,以便它与其他 CSS 的处理方式相同。

这些相同的显示问题也扩展到打印。测试打印样式表如何处理 SVG,并确保它们正常显示,并确保它们可见且比例正确。如果打印,搜索图标将与我们的网页示例中一样大,并且比例不正确 - 浪费纸张并影响可读性。


结论

现在,您可以选择任何 SVG,按照此过程进行操作,并知道您已经找到了具有最小文件大小的版本 - 考虑到您的起点。可能存在更好的方法,我可能遗漏了一些内容,而且情况肯定会有所改变,但我提供此方法作为一种可能的解决方案,并且希望它至少能够引发一些讨论,并促使您创建自己的方法。

即使您没有严格遵循此方法,考虑这些原则也可以帮助指导您的过程和工作流程。视觉检查是主观的,决定视觉保真度和文件大小节省之间的正确平衡 - 以及您为此付出的努力 - 取决于您。使网站具有高性能有很多优势,精简 SVG 可以为此做出重大贡献 - 最重要的是内联 SVG。

一个自动化工具将很有帮助,而且最好是像 SVGOMG! 这样的工具 - 已经广泛使用并且正在积极开发 - 将此类功能添加到他们的技巧包中。在此之前,我希望您决心从 SVG 中获得最大的回报。