我最近参与了一个项目,该项目流量很大,但用户流失率很高,因为页面加载时间过长,**大约 10 秒**。他们找我帮忙是因为该网站上的大部分图片都是 SVG,而且是动画的。我培训了团队如何**减小 SVG 的文件大小**,同时保持外观和功能,最终将加载时间缩短到**不到 2 秒**。跳出率大幅下降,转化率恢复正常。
如果我自己设计这些 SVG,我可能不会遇到很多这些问题,但更有可能的情况是,在一个项目中工程师和设计师不是同一个人。在这篇文章中,我将记录我培训他们的一些内容,以确保 SVG 的出色性能。
注意:我使用 Illustrator 创建和优化我的 SVG,因为我发现它的导出和工具优于 Sketch。我欣然承认,Sketch 可能有一些我所不知道的处理 SVG 的方法。但我必须说,我见过它在路径的位置生成奇怪的<clippath></clippath>
,这让我避开了它。在下面的示例中,我将使用 Illustrator。使用任何适合你的工具。
提前沟通
这部分内容并非总是可行,但只要可行,请尝试在设计师完成大量工作之前与他们沟通,解释他们在创建 SVG 时应该考虑什么。
最容易传达的部分应该是,简单地在纸上画一些东西,然后在 Illustrator 中描摹它会带来很多垃圾路径数据,并且绝不应该按原样使用。**首选简单的形状和钢笔绘制路径。**非常复杂的物体可能会很快变得很大,因此路径需要绘制的点越少,对性能越好。
这并不意味着你不能创建看似复杂的形状。但数百个路径点有时可以具有与数千个路径点相同的外观和趣味性。
减少路径点
如果你要创建手绘图,你可以进行描摹,但在那之后,你应该使用对象 > 路径 > 简化。

你需要选中允许预览的复选框,因为这可能会破坏图像。还需要说明的是,图像会快速退化,因此我通常最多只能使用 91% 左右。这仍然能给我带来良好的回报,并减少大量路径点。
这可能也是实现此类减少的最快捷方法。我将用于较小且不必要复杂的部分的另一种劳动密集型方法是使用钢笔工具重新绘制它。

有时这只需花费很少的精力就能获得很大的回报,但这确实取决于形状。你还可以将几个形状组合在一起,使用路径工具将其合并,然后使用白色箭头修改点,以模拟现有的形状。

起初这可能看起来令人生畏,但你可以使用钢笔工具非常快速地创建更复杂的区域。然后获取所有这些形状,并使用路径查找器工具将它们全部合并在一起。如果看起来不太正确,不要害怕!你仍然可以稍微降低你所创建内容的不透明度(这有助于你看到你在下面形状中试图模拟的内容)。然后,你可以抓住直接选择工具(快捷键为 A,工具栏上的白色箭头),并将这些小点拖动到周围,直到得到更精细的形状。放大一点以查看那里的细节总不会有错。

移除重复的渐变定义
默认情况下,Illustrator 和其他矢量编辑工具充其量会创建一个渐变并将其放入defs
中,但最糟糕的是,会创建渐变的 jpg 或添加许多单独的渐变,即使只有一个可以重复使用。在后一种情况下,请使用Jake Albaugh 的渐变优化器。这是一个智能工具,它会将多个未使用的渐变折叠成仅必需的渐变。我见过它将 SVG 的文件大小减少了一半,尽管那是一个具有异常数量的相似渐变的文件。
在前一种情况下,你可能会发现你可以手动编写渐变,而不是使用编辑器提供的 png 或 jpg。以下是 SVG 创建渐变所需的属性值
- 它需要包含在 linearGradient 块中,并且需要有一个 id,以便你可以在 CSS 中引用它以将其应用于 SVG 元素
- 它使用 0-1 之间的停止偏移量以及 stop-color 属性,在其中指定你希望在哪些点使用哪些颜色。
<defs>
<lineargradient id="linear-gradient" y1="75" x2="150" y2="75" gradientunits="userSpaceOnUse">
<stop offset="0" stop-color="#fff33b">
<stop offset=".5" stop-color="#f17b3e">
<stop offset="1" stop-color="#e93e3a">
</stop></stop></stop></lineargradient>
</defs>
.path-class { fill: url(#linear-gradient); }
减小画布大小
使画布不太大也不太小有助于文件大小,因为数字越大,所有路径点的数量就越大。太小,你可能会得到很多小数,这些小数在修剪时会扭曲图像。如果你有一个不错的范围(我更喜欢 100 x 100 左右,但这值得尝试),你的路径点也会很小,而不会分解成小数。
要在 Illustrator 中快速更改画板(SVG 中的 viewBox)的大小,你可以转到对象 > 画板 > 适应图稿边界。有时你可能需要更精确一些,在这种情况下,请转到文件 > 文档设置 > 编辑画板。这将允许你手动调整可见区域,甚至精确指定所需的单位。你可能还需要在之后稍微更改图稿的大小。
导出,然后优化
我更喜欢使用 Illustrator,因为它的 SVG 导出设置比 Sketch 更高级。我不使用 Inkscape,但我知道有些人喜欢它。如果你使用的是 Illustrator,请使用另存为 > SVG,而不是存储为 > SVG,以获得更好的效果。但是,即使在执行此步骤后,我也会进行优化。以下是一些选项
- SVGOMG – 这是一个基于 Web 的编辑器,它使用 SVGO,它还提供服务工作者以实现离线功能
- SVGO/SVGO-GUI – 这个基于 NodeJS 的工具做得非常好,并且有很多选项。我建议使用它的 GUI,因为 SVG 导出可能会改变其外观。
- Peter Collingridge 的 SVG 编辑器 – 我仍然喜欢这个,即使它没有那么花哨。我也喜欢玩实验编辑选项卡。
请注意这里的切换按钮。我发现自己最常选中和取消选中的是
- 清理 ID – 这将删除你可能精心命名的任何图层。
- 折叠无用组 – 你可能已将它们分组以一起设置动画,或者只是为了保持组织。
- 合并路径 – 十次中有九次这个没问题,但有时合并大量路径会阻止你在 DOM 中独立移动元素。
- 美化 – 这仅在需要在 SVG 内工作时(用于动画或其他操作目的)才必要。
最后,确保你正在压缩文件(我通常在整个构建过程中执行此操作),但这对于 SVG 文件大小来说有很大的影响。
使用 SVG 滤镜代替外观效果
在处理其他设计师的 SVG 时,我们发现了几次使用外观面板中的效果(如投影)会生成一个庞大的 base64 文件,该文件笨重且开销大。可以通过使用 SVG 滤镜来解决此问题,该滤镜位于效果 > SVG 滤镜,然后从下拉列表中选择一个。值得一提的是,只有当文件为 .ai 格式时,这些滤镜才能使用,而不是在文件为 .svg 格式时(这就是为什么我建议始终保留 .ai 源文件的原因)。通过交换这些滤镜,我们不仅改进了 SVG 的外观,而且将文件大小从惊人的1.8MB 减少到 1.2KB!

创建一个大型背景形状
在描摹图像时,你经常会遇到带有图案或多个图像“叠加”在背景上的图像。但是 Illustrator 不会将这些形状理解为图案或其他许多形状下方的单个大形状——它会将底色分解成图案之间的形状。

这是一个简单的例子,因为你可以移除所有这些形状,并用一个大的背景图像替换它。我发现最简单的方法是在移除任何内容之前,先描摹整个包含单元的轮廓。请记住,将此图层设置为与其他所有内容不同的颜色。
很多时候,后面的形状可以通过使用**选择 > 相同 > 填充颜色**(或填充和描边)一次性选中。这允许你一次性选中多个形状,并非常快速地一次性删除它们。

结论
这些并不是处理 SVG 以获得更好性能的唯一方法,但主要的要点是路径数据越少越好。注意你正在 SVG 文件中加载的内容——仔细检查 SVG DOM 中是否有冗余内容,并记住进行优化。在设计时为性能多加努力可以节省网站页面加载的关键时间。
我猜像素预览,然后调整到像素网格上,会有所帮助。更少的 fractions 和对细节程度的良好了解。
这里有一些很棒的信息!在 Illustrator 中进行手动描摹的一个快速技巧:将你的草图/源图像设置为模板图层(转到图层选项或双击图层)。这会锁定并使其变暗,以便你可以在下方放置路径图层并查看你的操作。
我发现一个用于 Illustrator 的插件对于优化 SVG 不可或缺——Vector Scribe (http://astutegraphics.com/software/vectorscribe/)。它有点贵,但它在处理用于网页的 SVG 时节省的时间非常值得。
这个 GIF 非常棒
哇,这太不可思议了!
这就是为什么我大部分 SVG 代码都是手动编写的。大多数所见即所得编辑器会很快膨胀文件。其他膨胀点:路径通常可以用预定义的形状元素来表达;路径点通常是具有荒谬精度(想想 10-20 位小数)的浮点数,四舍五入吧!许多矢量客户端会导出仅对该客户端有意义的命名空间和属性(例如 inkscape 和 sodipodi 元素/属性,几乎总是可以删除以节省 20-30% 的文件大小。最后,因为这是一个值得一提的简单技巧,当直接将 SVG 作为图像文件提供服务时(而不是直接嵌入到 html 中或作为 data URL 格式):基于 XML 的内容 gzip 压缩效果非常好。甚至还有一个专门用于压缩 svg 文件的文件扩展名,大多数浏览器无需处理 HTTP 标头或 Apache 设置即可处理:svgz。使用它,从 1.8MB 降至 1.2KB 的惊人效果会降至 .5KB(注意:我最后提到压缩是因为它很容易解决,但应该是在实际清理 svg 内容本身之后的优化最后一步)。
哦,另一个让我恼火的地方:不要定义文本元素并且在上面也绘制文本。在 99% 的情况下,仅使用文本元素就可以了,并且可以节省大量绘制客户端已经可以通过字体处理的字母的精力。
Gzipping 绝对是关键,我应该提到这一点——我是在假设人们已经在构建过程中使用了它,但这有时并非如此。
在文本方面,我看到 SVG 文本在不同浏览器之间存在很多非常奇怪的不一致现象(我在看着你,Safari),所以我倾向于在进行大量检查后,逐个案例进行处理。
舍入是 Illustrator 导出过程的一部分,也是 SVGOMG 的长处,所以我没有在解释中详细说明这一点,但这是一个很好的补充。
感谢所有有用的信息!
你可能对尝试 Boxy SVG 编辑器感兴趣,它生成的 SVG 文件比 Inkscape 更干净。
它支持打开和保存 SVGZ 文件,并允许你配置几何精度。它使用专有的 bx: 命名空间,但仅在绝对必要时才能保留编辑功能。
哦,还有
你能分享 spidertocat 图像的最终 SVG 吗?我很想直接查看原始 XML。
感谢 Sarah 提供这些信息。
实际上,不需要。
<defs>
的目的是放置参考元素而不进行渲染。像渐变这样的非渲染元素可以完全安全地放置在任何地方。无需添加<defs>
元素只是为了放置渐变和其他非渲染内容。关于 SVGO(MG):如果没有 **清理 ID**,它将不会删除未使用的元素,因为它根据
id
的存在来判断元素是否正在使用。**清理 ID** 删除了未引用的 ID。总的来说,这篇文章很棒!
好的,我会更新文章。谢谢!
从 SVG 2 开始,渐变可以安全地放置在几乎任何地方,尽管浏览器尚不支持 SVG 2 内容模型,这意味着你不能将它们放在例如形状元素内部。
很棒的文章。Illustrator 也是我的首选。有时我会使用 Sketch,但我更喜欢 PC。此外,在我看来,Illustrator 在网页方面效果更好。
如何使用带有 JavaScript 可访问性的外部 svg sprite。
很棒的技巧,非常感谢。
使用符号表示重复元素怎么样?这会带来任何性能提升吗?它绝对使处理结果代码变得简单得多。
你知道,几年前我做过一个关于带有符号的 SVG 的性能基准测试,但没有看到任何明显的性能提升,但那是两年前的事了,而且是针对动画的,所以我可能需要重新运行它并进行更正式的测试。或者,你也可以自己做。CSS-Tricks 上的一位评论者在 React 中渲染与符号中渲染之间看到了很大的性能提升,如果这对你有帮助的话。