SVG不擅长些啥

871 阅读7分钟

上一篇《SVG擅长些啥》里,每每说到那些功能时,都要好好的拉踩一下CSS,毕竟是SVG的专场嘛,不过,所谓金无足赤人无完人,技术也同理,SVG在实际生产的使用过程中,也有着很多让人使用体验极差的地方,每到这时都忍不住感叹一句,这要是CSS就好了,今天我们就为CSS鸣个不平,一起来细数一下那些SVG力不从心的地方。

一、文本呈现

说到文本呈现,当今的前端领域CSS尚未遇到过敌手,这是人家吃饭的本事,但是用惯了CSS简单无脑的处理后,就会越发的体会到SVG在文本处理上的吃力。

文本居中

33.png

<svg width="200" height="100" viewBox="0 0 200 100">
  <text x="50%" y="50%" fill="grey" font-size="40">SVG</text>
</svg>

SVG中想实现一个文字居中是很麻烦的,由上图可以看到,x坐标会受到text-anchor影响,但y坐标是基于文字底部计算的,所以就呈现出了y坐标为50%时,文字表现为如此的原因了。

那么,想要文字水平垂直居中应该如何处理呢?

水平方向可以设置text-anchor="middle"来实现,至于垂直方向有两种方式可以实现:

  1. 调整dy偏移量来实现:
<text x="50%" y="50%" dy="15" text-anchor="middle">SVG</text>
  1. 直接调整y坐标到居中
<text x="50%" y="65%" text-anchor="middle">SVG</text>

然而,SVG的文字居中相较于常规的文字处理操作,也只能相形见绌了。

文本缩略

34.png

超出容器长度之后显示缩略…,对于CSS来讲只能算是入门范畴,几个简单的CSS属性就可以完美搞定。

.text-cut { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

但是,CSS的基操勿6,放在SVG的语境下却只能望洋兴叹,当然方法也不是没有:

JS暴力破解:通过JS来获取字符串长度或者通过Canvas来获取到字符串宽度,再与容器宽度比对之后,手动截取字符串,最后再拼接上

是不是光是看描述都已经头大了,更何况单纯通过字符个数或宽度来截取并不是个优雅的方案,因为中文字符和英文字符的个数是不一样的,而且不同字体的宽度也并不一致,所以这仅仅是一种下位替代的无奈之举。

那有没有完美的解决方案呢?

答案是肯定的,就是在SVG中写HTML,通过 <foreignObject> 这个标签来实现SVG中写入XML 命名空间其他的元素,HTML就包含其中,具体实现如下。

35.png

p {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size:12px;
    margin: 0;
}
<svg width="200" height="100" viewBox="0 0 200 100"
		 xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="120" height="50">
        <body xmlns="http://www.w3.org/1999/xhtml">
          <p>这是一段会被缩略的文字</p>
        </body>
      </foreignObject>
  </svg>

这样就可以相对优雅的解决了,但优雅的来源却是将SVG语境下的难题放到了CSS的语境下而已。

文本换行

和文字缩略一样,SVG对于文本的处理几乎是束手无策的状态,比如一段长文本想要折行,基本只能手动通过两个<tspan> 来实现,<tspan> 可以理解为HTML中的<span>

36.png

<svg xmlns="http://www.w3.org/2000/svg">
  <text font-size="12">
    <tspan x="0" y="10">一段需要word wrap</tspan>
    <tspan x="0" y="26">的文字。</tspan>
  </text>
</svg>

如此愚蠢的实现在CSS中是无法想象的,当然,如果是Chrome浏览器可以通过对 <text>标签进行 white-space: normal 强制设置,但也只是Chrome浏览器可以。

不过,既然缩略可以通过<foreignObject> 来实现,那么折行放到HTML+CSS的语境下也是小菜一碟了。

37.png

<svg xmlns="http://www.w3.org/2000/svg">
    <foreignObject width="120" height="50">
        <body xmlns="http://www.w3.org/1999/xhtml">
          <p style="font-size:12px;margin:0;text-align: left;">
            一段需要word wrap的文字。
          </p>
        </body>
    </foreignObject>
</svg>

同理,文字居中依旧可以通过 <foreignObject> 标签来更加优雅的实现,不过,虽然这几个问题都在SVG环境下得到了解决,但文字处理和呈现上依旧是SVG的痛点,我们也只是将SVG无法处理的问题,转移到了更加擅长的CSS战场上来,属于降维打击了。

二、持续性动画性能不佳

首先明确一点,这里指的动画性能不佳主要是指重复性动画,1次性动画并不是本次的讨论范围。

有了故事背景之后就好办了,我们先用CSS来实现一组动画,然后重复20次。

38.gif

OK,现在看下CSS-animation的性能如何。

39.jpg

嗯,怎么说呢,这点性能占用说是微乎其微都有点严重了。

再来看看SVG-animation的实现效果呢?

40.gif

41.jpg

同样是前端技术,做动画的差距怎么就这么大呢?这要是算个倍数关系都算是欺负SVG了。

不过,SVG-animation的性能欠佳,也跟Chrome没有针对它做过优化有关,感觉Chrome一直都对SVG颇有成见,不知道是不是早期结过什么梁子,至于其他浏览器并没有做过测试,想来Chrome都选择躺平,其他平台想来也是大差不差。

好了,让我们顺道来对前端常用动画方案做个总结:

CSS-Animation

优点:

  1. 性能极佳(遵循CSS动画优化原则
  2. 持续性动画的首选方案前提是涉及的DOM元素不宜过多
  3. CSS驱动,不会被主线程阻塞

缺点:

  1. 对于异型、多边形、圆形CSS绘制圆形有时会被挤压为椭圆)等复杂图形实现难度较高

  2. 对于复杂动画,尤其是同一时间进行很多动画效果的实现,例如(高斯模糊&&缩短 -> 发光&&变色)实现效果不佳

  3. 对于过多元素的动画(例如散点、bar或路径图的箭头),CSS的性能消耗过大

  4. animation中如果依赖一个动态属性(如宽度等),需要动态修改@keyframes中的值,则需要修改styleSheets.insertRule去实现的(极不推荐),当然随着浏览器对新技术的兼容性提升,这个问题可以被CSS变量优雅的解决

SVG-Animation

优点:

  1. 对于复杂&&元素不多&&一次性的动画几乎是最高效的解决方案

  2. CSS一样不会被主线程阻塞

缺点:

  1. 对比CSS实现相同的持续性动画的性能消耗极高(持续性动画不推荐)

  2. CSS一样,对于多DOM节点的动画性能消耗过大

  3. 部分浏览器兼容性不佳

  4. 当使用CSStransform来操作SVG时,操作的并不是SVG中的某一元素,而是整个<svg>标签,当然这点可以通过使用SVG自带的transform来解决,不过也会带来其他的麻烦,我们再下一篇会详细介绍

Canvas

优点:

  1. 解放GPU的性能消耗,压力转移到了CPU

  2. 不在担心CSSSVG动画回流重绘时带来的巨大性能消耗

  3. 可以配合WebWorker进一步对性能进行优化

  4. 可以实现极其复杂的动画效果

缺点:

  1. 实现复杂有难度(canvas要有一定得敬畏之心),不能手里拿个锤子,看什么都像钉子

  2. 不同于CSSSVG的自动驱动,Canvas的动画需要通过RAF或者setTimeout或者setInterval来驱动,所以可能会被主线程阻塞

  3. Canvas的动画需要通过逐帧的(擦除 <=> 绘制)循环来实现动画的效果,所以需要进行大量的计算,从而可能会阻塞主进程

三、不能整体布局

这点很好理解,SVG每个标签中除了极其特殊的标签例如 <text><tspan> 之外,几乎都不能嵌套使用,所以也不存在层级关系,只是相同位置的标签,后面的标签会覆盖在之前的标签之上,也就是书写顺序决定index的关系,仅此而已,所以,HTML中的流体性、自适应性、弹性等等,SVG都享受不到,再加上对文本处理上的捉襟见肘,使得SVG根本就无法适应如今复杂多样且要求适配不同分辨率的复杂布局,说的再直白一些,SVG不是布出来的而是出来的。

不过话又说回来,SVG本身也只是为了图形而生的技术,只要在自己的专长领域遗世独立就足以让人心向往之了。

好了,我们目前已经了解了《SVG是个啥》《SVG擅长啥》和今天的《SVG不擅长啥》,基本已经可以根据现有知识来对需求场景进行分析是否应该使用SVG以及应该使用SVG的哪个方案了,接下来,我们要来一点点进阶,了解一下《SVG中的奇淫巧技》以便日后对SVG更有掌控性,让工作变的事半功倍。

参考文档

SVG 简介与截图等应用