使用“use”元素超越自动SVG压缩

Avatar of Mariana Beldi
Mariana Beldi

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

如果您自己绘制SVG文件或从互联网下载SVG文件,那么像 SVG-EditorSVGOMG 这样的工具就是您的好帮手。使用这些工具压缩文件只需几秒钟,即可大幅减少文件大小。但是,如果您需要内联使用SVG进行动画或与代码交互,那么在代码可读性方面仍然有很多可以做的事情。

使用SVG的<use>元素重用内容并不总是可行的,但当它可用时,您不会后悔花几分钟时间将其付诸实践。

在本文中,我将展示一个我能够充分利用此元素的示例——不仅是为了减少文件大小,而且还使标记更清晰,更易于阅读和维护。

这是我需要处理的第一个设计。它最初是在Illustrator中创建的。

请查看以下代码,这是直接从软件导出的原始文件,大小为2.05kb

它根本不是一个很大的文件。但是,打开它,您会发现有很多空标签、已弃用的命名空间、不必要的空格、逗号和软件应用的额外信息。这使得代码难以使用,扫描起来很烦人,并且在文档中数百行代码中造成了很大的滚动。

您还会注意到,该文件确实使用了<use><defs>元素,但不是以最佳方式使用。这不能怪软件!原始文件中的每个宇航员插图都有一个剪切蒙版:一个无形的圆圈,充当窗口,我们可以通过它看到我们的角色。如果没有它,宇航员的宇航服就会溢出圆圈之外。在Illustrator中有几种方法可以避免这种情况,例如使用路径查找器选项裁剪这些多余的部分。这样,我们可以节省一些字节,并避免仅为我们不会显示的图形的剪切信息使用额外的圆圈。文件的压缩始于软件。 尽管如此,如果我们不想编辑原始文件,我们仍然可以在代码上进行很多改进。

使用SVGOMG压缩SVG并保留默认选项不需要任何努力,您将获得一个大小为1.46kb的文件。与原始大小相比,这减少了30%,并且图形看起来完全相同。

重用内容

这将需要遍历SVG并进行一些调整。我知道与前面的示例相比,此选项需要更多时间,但它并不像看起来那么难。

我们有一个重复的元素,即圆圈内的宇航员。这就是我们在SVGOMG上压缩的那个。结果将如下所示

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 95.8 95.8">
<style>.st3,.st4{fill:#ffcb2f;stroke:#12192c;stroke-width:1.4891;stroke-miterlimit:10}.st4{fill:#69b2b1}</style>
<circle cx="47.9" cy="47.9" r="47.9" fill="#12192c"/>   
<circle cx="47.9" cy="47.9" r="40.7" fill="#f6a2a4"/>   
<defs><circle id="SVGID_1_" cx="47.9" cy="47.9" r="40.7"/></defs>   
<clipPath id="SVGID_2_"><use xlink:href="#SVGID_1_" overflow="visible"/></clipPath>
<g clip-path="url(#SVGID_2_)">     
<path class="st3" d="M63.9 45.6H32c-4 0-7.2 1.9-7.3 4.3l-.8 26.6H72l-.8-26.6c-.2-2.5-3.4-4.3-7.3-4.3z"/>     
<path class="st4" d="M74.3 86.9L66 88.2C53.8 90 41.4 90 29.1 88.1l-7.7-1.2v-14c0-4 3.2-7.2 7.2-7.2h38.5c4 0 7.2 3.2 7.2 7.2v14z"/>     
<path class="st3" d="M31.8 47.3h-.6c-.7 0-1.2-.6-1.2-1.2V23.2c0-.7.6-1.2 1.2-1.2h.6c.7 0 1.2.6 1.2 1.2v22.9c0 .7-.6 1.2-1.2 1.2z"/>     
<circle class="st4" cx="31.5" cy="20.7" r="2.8"/>     
<circle class="st4" cx="47.9" cy="51.4" r="20.3"/>     
<path d="M64.5 53.1c0 8-7.4 11.2-16.5 11.2S31.4 61 31.4 53.1s7.4-14.4 16.5-14.4 16.6 6.4 16.6 14.4z" fill="#13192d" stroke="#12192c" stroke-width="1.489" stroke-miterlimit="10"/>     
<path fill="none" stroke="#12192c" stroke-width="1.489" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" stroke-dasharray="9.6793,3.7228" d="M65.9 88V76.9"/>     
<path fill="none" stroke="#12192c" stroke-width="1.489" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="M29.6 87.9v-11"/>   
</g> 
</svg>

首批建议:

  1. <style>内容移动到CSS文件中(假设您可以内联使用SVG,并且您的文档中链接了样式表)。
  2. 使用对您有意义的内容重命名ID。
  3. 舍入那些复杂的数字,例如将stroke-width="1.489"舍入为stroke-width="1.5"。如果您在Illustrator中调整矢量大小并选中缩放边框选项,则可能会发生这种情况。
  4. 删除stroke-miterlimit="10",因为我们不需要它,因为我们的stroke-linejoin是圆形的。
  5. 此代码将是我们的宇航员模板。我们需要将所有内容包装在一个组中,向该组添加一个ID,并将其放置在<defs>标签内。请注意,我们已经有一个包含圆圈的<defs>元素。我们可以删除它,因为它将成为更大的<defs>标签的一部分。

请注意,前两个圆圈是具有不同半径和颜色的填充形状。我们可以保留较小的那个,并添加一个足够大的描边以达到相同的效果——同样,这是我们在Illustrator中最初可以使用带边框的圆圈避免的事情。

另一件重要的事情是,我们当前的viewBox对于我们想要构建的内容来说太小了。让我们将其放大,并在X轴上添加一些负空间,以便我们可以从中间开始克隆我们的宇航员。

要了解有关viewBox的更多信息,请查看Amelia Wattenberger编写的这篇优秀的指南,了解如何缩放SVG。

最终结果将如下所示

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-400 0 1000 5000">
 <defs>
  <g id="astronaut">
   <circle cx="94.5" cy="48" r="44" fill="currentColor" stroke="#12192c" stroke-width="8"/><clipPath id="a"><circle cx="94.5" cy="47.9" r="40"/></clipPath>
   <g clip-path="url(#a)"><path class="st3" d="M110.5 45.6H78.6c-4 0-7.2 1.9-7.3 4.3l-.8 26.6h48.1l-.8-26.6c-.1-2.5-3.4-4.3-7.3-4.3z"/><path class="st4" d="M121 86.9l-8.3 1.3C100.4 90 88 90 75.8 88.1l-7.7-1.2v-14c0-4 3.2-7.2 7.2-7.2h38.5c4 0 7.2 3.2 7.2 7.2v14z"/><path class="st3" d="M78.4 47.3h-.6c-.7 0-1.2-.6-1.2-1.2V23.2c0-.7.6-1.2 1.2-1.2h.6c.7 0 1.2.6 1.2 1.2v22.9c0 .7-.5 1.2-1.2 1.2z"/><circle class="st4" cx="78.1" cy="20.7" r="2.8"/><circle class="st4" cx="94.5" cy="51.4" r="20.3"/><path d="M111.1 53.1c0 8-7.4 11.2-16.5 11.2S78 61 78 53.1s7.4-14.4 16.5-14.4 16.6 6.4 16.6 14.4z" fill="#13192d" /><path fill="none" stroke="#12192c" stroke-width="1.5" stroke-linecap="round" d="M112.5 88V76.9"/><path fill="none" stroke="#12192c" stroke-width="1.5" stroke-linecap="round" d="M76.3 87.9v-11"/></g>
  </g>
 </defs>
</svg>

<defs>内部的内容不会在任何地方渲染。要开始克隆我们的宇航员,我们需要像这样在其内部链接其ID到<use>元素中

<use xlink:href="#astronaut"/>

xlink:href自SVG2以来已被弃用,但最好出于兼容性目的使用它。您可以在现代浏览器中使用href,但我已在Safari上对其进行了测试,截至撰写本文时,它无法正常工作。如果您使用xlink:href,请确保在您的SVG标签中包含此命名空间:xmlns:xlink="http://www.w3.org/1999/xlink(如果您决定使用href,则不需要它)。

现在,我们可以向此第一个图形添加相应的文本,并使用transform属性对其进行对齐。我们最好将这两个元素都放在一个组内,以便将来我们可以将整个组转换为我们想要的位置

<g transform="translate(-95 210)">
  <use xlink:href="#astronaut"/>
  <text transform="translate(25 130)">Tech Leader</text>
</g>

连接线是简单的形状,可以使用<path>直接绘制。路径看起来很吓人,但对于矩形线,无需担心太多。我将解释此代码

<path class="line" d="M-4 200v-25h200"/>

d=""用于数据,我们将在其中放置我们的命令。M用于将我们的手移动到我们将开始绘制的地方(但它没有绘制任何东西)。-4 200表示我们将铅笔向左移动四个单位,向下移动200个单位到我们的viewBox(遵循SVG坐标系的方位)。v是开始绘制垂直线的命令,该命令将从此处向上移动-25个单位。h用于水平线,因此我们从那里向右绘制一条200个单位的线。感觉就像Logo设计软件。

我将线条分成了三条路径,但我们只需使用一条,在命令序列后使用M值,即可将我们的手移动到坐标系中的新点并开始从该点绘制。

请查看最终文档。现在文件大小为779字节,并且有12行易读且可扩展的代码

如果我们在<defs>中定义的属性中声明任何值,那么由于<use>元素的性质,将无法在其克隆中更改它。这就是为什么在上面的示例中,主圆圈的填充被替换为currentColor的值,以便控制所有复制项的背景。currentColor将继承元素(或其上方的任何元素)的CSS颜色值。在SVG中,我向一些复制的宇航员添加了一个类,并在CSS中向这些类添加了一个颜色值。这样,我就可以更改具有该类的<use>元素的所有实例。要了解有关<use>以及如何对其内容进行样式设置的更多信息,这篇帖子Sara Soueidan撰写,其中包含您需要了解的所有内容。

使用此准备好的代码,我们可以更轻松地将图形扩展到类似这样的内容

SVG组织结构图(演示

以下是三个并排的示例,用于比较可读性和代码量,我们从241行减少到10行整洁的代码

从左到右:直接来自Illustrator的代码、SVGOMG处理后的代码、优化后的代码。