线条之美,玩转SVG线条动画

5,016 阅读7分钟

什么是线条动画

通常来说,对于web前端来实现动画效果,不外乎通过下面几种方案:

  • CSS动画:利用css3的样式效果可以将dom元素做出动画的效果来。

  • Canvas动画:利用Canvas提供的API,不断清除--绘制这样一帧一帧的做出动画效果。

  • SVG动画:SVG意为可缩放矢量图形,同时也是HTML中的一个标签,在实现动画方面较为小众了一些,但其提供了不少的API来实现动画效果,并且兼容性也不差。

而线条动画是一种以线条或者路径为主要元素,利用各种组合和动作实现的动画效果,通常使用SVG的<path>路径来实现,本文主要讲解一下如何制作SVG线条动画。

先来看几个demo:

以上这些效果都是利用SVG线条动画实现的,结合了css3和SVG相关的API,没有使用到一行JavaScript代码,和Canvas比起来要容易一些,下面就说明一下实现这些效果的原理。

SVG的基础知识

SVG主要以<svg>标签的形式在HTML文档中呈现,例如:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
  <circle cx="100" cy="50" r="40" stroke="black"
  stroke-width="2" fill="red" />
</svg>

其相关的API和Canvas非常像,提供了包括文本,直线,矩形,圆形,曲线,路径等等相关形状的绘制,同时也包括了一些滤镜,阴影,渐变等一些效果,但是和Canvas不同的是,SVG作为网页中的标签,是会被CSS3等样式或者动画的相关参数影响的,借助这一点实现SVG的路径动画就会简单很多。 这里我们只介绍<path>相关的参数,其他更多关于SVG的API教程,推荐去官网来学习了解。

路径<path>:

<path>元素是SVG基本形状中最强大的一个,它不仅能创建其他基本形状,还能创建更多其他形状,例如贝塞尔曲线、2次曲线等曲线。<path>元素的形状是通过属性 d 来定义的,其值是一个“命令+参数”的序列,规则如下:

<path>元素d属性命令:

M = moveto(M X,Y) :将画笔移动到指定的坐标位置
L = lineto(L X,Y) :画直线到指定的坐标位置
H = horizontal lineto(H X):画水平线到指定的X坐标位置
V = vertical lineto(V Y):画垂直线到指定的Y坐标位置
C = curveto(C X1,Y1,X2,Y2,ENDX,ENDY):三次贝赛曲线
S = smooth curveto(S X2,Y2,ENDX,ENDY):平滑曲率
Q = quadratic Belzier curve(Q X,Y,ENDX,ENDY):二次贝赛曲线
T = smooth quadratic Belzier curveto(T ENDX,ENDY):映射
A = elliptical Arc(A RX,RY,XROTATION,FLAG1,FLAG2,X,Y):弧线
Z = closepath():关闭路径

利用<path>的这些命令我们可以实现我们想要的任何线条组合,以一段简单的线条为例:

<path id="path" fill="none" stroke="#000" stroke-width="1px" d="M452,293c0,0,0-61,72-44c0,0-47,117,81,57
    s5-110,10-67s-51,77.979-50,33.989"/>

效果如下:

看起来很简单,但是,如何让这个线条动起来呢?这里就要用到SVG里的<path>的一些主要属性:

  • stroke:标识路径的颜色。

  • d:标识路径命令的集合,这个属性主要决定了线条的形状。

  • stroke-width:标识路径的宽度,单位是px。;

  • stroke-dasharray:它是一个和数列,数与数之间用逗号或者空白隔开,指定短划线和缺口的长度。如果提供了奇数个值,则这个值的数列重复一次,从而变成偶数个值。因此,5,3,2等同于5,3,2,5,3,2。

  • stroke-dashoffset:标识的是整个路径的偏移值。

stroke-dasharray和stroke-dashoffset

实现线条的动画,核心是利用stroke-dasharraystroke-dashoffset这两个属性,对于stroke-dasharray可以参考下图来理解:

stroke-dashoffset则可以理解成类似translate的偏移值。通过CSS来设置这两个值,之前的路径就会变成这个样子:

#path {
        stroke-dasharray: 3px, 1px;
        stroke-dashoffset: 0;
}

效果:

下面就可以分别利用这两个属性并结合CSS3的animation来让线条动态的绘制出来,从而实现简单的动画。

#path {
    animation: move 3s linear forwards;
}
 
@keyframes move {
      0%{
          stroke-dasharray: 0, 511px;
      }
      100%{
          stroke-dasharray: 511px, 0;
      }
}

效果:

511px这个值是整个路径的长度,可以用DOM的API来获取到:

document.getElementById('path').getTotalLength()

stroke-dasharray: 0, 511px表示实线和空隙的长度分别为 0 和 511px,所以一开始整个路径都是空隙,所以是空的。 然后过渡到stroke-dasharray: 511px, 0 因为整个线条的长度就是 511px,而实线的长度也慢慢变成511px,所以整个线条就出现了。

同样利用stroke-dashoffset也可以实现这个效果,原理就是最初线条分为511px实线,和511px空隙,但是由于设置了offset使线条偏移不可见了,当不断修改offset后,线条慢慢出现。

#path {
    animation: move 3s linear forwards;
    stroke-dasharray: 511px,511px;
}
 
@keyframes move {
  0%{
      stroke-dashoffset: 511px;
  }
  100%{
      stroke-dashoffset: 0;
  }
}

效果:

复杂的Path路径

当我们掌握了上述的方法后,整个利用SVG实现线条动画的原理就已经清楚了,我们需要的就是一个SVG路径了,但是总画一些简单的线条还是不完美啊,那我们如何才能得到复杂的SVG路径呢?

  • 找UI设计师要
  • 自己动手将图片导出SVG路径,只需要简单的2步

以苹果LOGO为例:

  1. 得到苹果LOGO的png图片。
  2. 在PS里打开图片,右键图层,然后点击从选区生成工作路径,我们就可以得到:

3. 文件–导出–路径到AI,将路径导出在AI里面打开:

  1. 在AI里面选择保存成svg格式的文件,然后用文本打开svg文件,将path的d拷贝出来即可。

  2. 利用上文介绍的实现动画的方法,我们就可以轻松的得到了下面这个效果。

线条动画进阶

可以看到上面的动画效果和文章最初显示的动画效果还是有区别的,要想实现文章最初的动画效果,需要用到SVG的<symbol><use>来实现:

SVG复用:<symbol><use>

在SVG中,<symbol>元素用来定义一个图形模板对象,它可以用一个<use>元素实例化。当同一个图形在SVG文档中多次使用时,就可以利用这两个元素。注意,一个<symbol>元素本身是不会有显示效果的。只有<symbol>元素的实例(一个引用了<symbol><use>元素)才能呈现出效果。

利用这个思路,我们可以将原本的一条路径复制多份进行叠加,同时设置上不同的颜色和动画延时,从而达到一种"追击线条"的动画效果,代码如下:

<svg version="1.1"
xmlns="http://www.w3.org/2000/svg">
<symbol id="pathSymbol">
    <path  class="path" stroke="#000"  d="M344,26c3.595,1.373,3.172,0.899,5,4c16.619,39.859-50.248,119.052-93,107c-0.572-46.929,22.555-81.661,53-98
  C320.666,34.667,332.334,30.333,344,26z"/>
    <path  class="path" stroke="#000"  d="M338,132c53.094-1.055,80.442,15.317,103,44c0,1.333,0,2.667,0,4c-40.96,30.44-66.713,87.897-34,147
  c6.417,11.595,21.062,26.807,32,34c5.333,2.667,10.667,5.333,16,8c-4.646,40.842-57.294,115.573-94,124
  c-31.519,7.236-54.682-11.118-77-16c-37.039-8.102-61.021,12.37-87,18c-35.953,7.792-63.181-27.32-76-45
  c-59.011-81.386-102.75-270.669,25-313c37.527-12.435,76.171,6.998,106,13C271.355,153.895,325.573,138.184,338,132z"/>
</symbol>
<g>
  <use xlink:href="#pathSymbol"
    id="path1"></use>
    <use xlink:href="#pathSymbol"
      id="path2"></use>
</g>

</svg>
      #path1 {
        stroke: #9C27B0;
        stroke-dashoffset: 7%;
        stroke-dasharray: 0 35%;
        animation: animation 3s linear forwards;
      }

      @keyframes animation {
          100% {
            stroke-dasharray: 7% 7%;
            stroke-dashoffset: 7%;

          }
      }

      #path2 {
        stroke: red;
        stroke-dashoffset: 7%;
        stroke-dasharray: 0 35%;
        animation: animation2 3s linear forwards;
      }

      @keyframes animation2 {
          100% {
              stroke-dasharray: 7% 7%;
              stroke-dashoffset: 14%;

          }
      }

效果:

上面代码,叠加了两份路径,同时设置了不同的stroke-dasharraystroke-dashoffset动画参数,从而实现了这种效果。

另外,可以直接将文本元素写在<symbol>中,会自动将文本文字转化为对应的path路径,如下:

  <symbol id="text">
    <text x="10%" y="35%" class="text">I</text>
    <text x="30%" y="35%" class="text"></text>
    <text x="60%" y="35%" class="text">U</text>
  </symbol>

通过设置font的一些属性,以及不同叠加路径的颜色搭配,就可以达到对文字添加线条动画的效果:

文中相关完整源码可以直接右键-开发者工具查看,尽情的发挥想象力来实现自己的SVG线条动画吧~