SVG Symbol 和 Sprite 的好处和坑

"I propose that the following character sequence for joke markers:

:-)

Read it sideways."
Scott E. Fahlman

SVG Symbol

用 Symbol 来把 SVG 合并到一个文件几乎是现在最流行的用法。

Symbol 好处

方便

利用 ID 来取图案,所以不用各种计算,可以随便放。

反复利用

这应该是一个不太容易发现的好处,你可以在文件内部继续用<use>来做图案的各种版本。这样 SVG 的优势更加明显,节省了好多空间。

比如这个博客里用到的社交图案,原本的是只有图案本身。例如这是 Codepen 的图案:

1
2
3
4
<symbol id="icon-codepen" viewBox="0 0 32 32">
<title>codepen</title>
<path class="icon-path" d="M17.050 1.259c-0.882-0.546-2.016-0.546-2.855 0.042l-12.764 8.649c-0.672 0.462-1.092 1.218-1.092 2.016v9.321c0 0.84 0.42 1.596 1.134 2.057l12.974 8.355c0.84 0.546 1.931 0.546 2.813 0l13.226-8.482c0.714-0.462 1.134-1.218 1.134-2.057v-9.153c0-0.84-0.42-1.596-1.134-2.057l-13.436-8.691zM26.959 11.378l-4.87 3.191-4.576-3.233-0.042-6.382 9.489 6.424zM14.11 4.954v6.256l-4.702 3.191-4.702-3.065 9.405-6.382zM3.446 14.401l3.023 1.973-3.023 2.057v-4.031zM14.195 27.753l-9.447-6.172 4.744-3.233 4.744 3.107c-0.042 0-0.042 6.298-0.042 6.298zM12.389 16.332l3.065-2.099 3.569 2.267-3.149 2.099-3.485-2.267zM17.553 27.753v-6.298l4.535-2.939 4.87 3.107-9.405 6.13zM28.302 18.557l-3.233-2.057 3.233-2.099v4.157z"/>
</symbol>

现在直接在文章里<use>

1
2
3
<svg fill="#000">
<use xlink:href="/images/symbol-defs.svg#icon-codepen" />
</svg>

就是这个效果:

symbol-defs.svg里还有它的另外一个版本,带圆圈的,只需要添加几行就可以:

1
2
3
4
5
<symbol id="icon-codepen-circle" viewBox="0 0 32 32">
<title>codepen</title>
<circle cx="50%" cy="50%" r="50%" fill="#000"/>
<use xlink:href="#icon-codepen" width="20" x="6" fill="#fff"/>
</symbol>

同样的使用方式,既环保又方便:

Symbol 坏处

不完全支持

这种方式并不完全支持 SVG 的各种特性。比如我开始就踩到了一个坑。我的 LOGO 里使用了clippath,使用这种方式就会失去效果。这个貌似是个陈年老 bug 来的。

解决方式就是利用工具合并路径,最好还压缩成一条,方便管理。编辑工具推荐 Boxy SVG,生成的代码非常轻盈,而且尽可能保留原来的样子,不会像 Illustrator 一样源码面目全非。压缩工具推荐 SVGOMG!,号称 SVGO's Missing GUI。

奇怪的宽高

在宽和高是百分比的情况下,会出现跟<img>或者普通<svg>不一样的计算。有时高空出一段,有时宽空出一段。

这个我纠结了很久,没有找到原因。我猜是受到原本整个 SVG 的影响。

解决方法是用相同宽高比的父<div>来限制;或者不用百分比。

因为零部件是可以<use>的,所以引擎不能像图片一样直接解析完就一整块到处扔。

虽然这个延时非常的小,一般几乎感觉不到,但是如果像这个博客左边的菜单栏一样(电脑上),在每个页面都是同样的元素,那么切换页面的时候就可以肉眼感受到图案的闪动。这种情况就只能放弃使用 Symbol。可以考虑单独一张 SVG 图片或者:👇

SVG Sprite

SVG Sprite 与以前的 PNG Sprite 一样,把图案按一定方式平铺到一张大图片上。

Sprite 好处

对齐

SVG 不受大小限制,所以 Sprite 可以按统一的规格排列。

取的时候也不受大小限制,利用百分比来取。

比如这个博客左边菜单的图案就是 SVG Sprite,利用 Sass 自动计算百分比

这种方式与普通图片一样肉眼看不到延时,而且还结合了 SVG 不受大小限制的优势。

Sprite 坏处

添加麻烦

图案受位置影响,当然没有 Symbol 方法来得方便。

因为需要快速显示的图案不多,我是利用 Boxy SVG 一个一个添加的。

不太用心的查过一下,没注意到有合适的自动化工具。

能用 Symbol 的当然优先使用 Symbol 方法,所以 Sprite 用的也不多,手动添加可以满足。

有误差

使用百分比因为受小数影响,图案会有1px浮动,当然这个1px是根据图案当前大小得出的,所以越小图案浮动的位置越大。

解决方法有两个,一是避免产生小数,按倍数来设置图案大小;二是按图案最小的情况计算出血,把图案缩小空出足够位置。

您还在局域网。 ——来自隔墙相望的评论