UI设计师福利之零基础入门SVG路径动画(看最后的更正部分)

先看一个动画效果,这种小飞机沿路径飞行(路径部分线段变成绿色是录屏软件出了问题)。json

plane
plane

这种动画效果最多见于发送信息后,两个不一样位置之间的导航指向等等,总之使用场景仍是不少的。对于SVG动画来讲,这种效果是最最简单不过,只须要一个路径外加几个属性的简单设置就能完成,简单到不算飞机图形的话,两句代码,而整个SVG文件只有1K左右大小,咱们由浅入深,从基础开始,开启SVG路径动画之门。bash

咱们把动画元素拆解一下,由两个部分组成,一个是路径,一个是沿路径运动的图形元素。svg

1.path路径得到

关于path路径,SVG官方的定义以下:函数

  • M = moveto
  • L = lineto
  • H = horizontal lineto
  • V = vertical lineto
  • C = curveto
  • S = smooth curveto
  • Q = quadratic Bézier curve
  • T = smooth quadratic Bézier curveto
  • A = elliptical Arc
  • Z = closepath
    这些还不是最恐怖的,最恐怖的莫过于下面的三次贝塞尔曲线和二次贝塞尔曲线Q。

三次贝塞尔曲线
三次贝塞尔曲线

二次贝塞尔曲线
二次贝塞尔曲线

各位UI设计师们,线性代数可还会?彻底不记得了?很好,由于上面这些吓唬人的知识在这个路径动画中通通用不着(你特么是在逗我?(¯﹃¯))(了解贝塞尔曲线的绘图原理多用于曲线非简单规律变化的复杂动画,不过如今有Airb
nb的Lottie神器了,用AE来作复杂的动画转成json文件是捷径,数学大神们除外。)
咱们说过了,AI里面的路径在导出SVG时一样会生成对应的<path>标签。若是你是第一次看个人关于SVG动画的文章也没有关系,咱们一步步分解。
第一步:AI绘制一条由起点A到终点B的曲线,随便描个边。工具


AI导出SVG的文件中,仅保留 <path>标签部分。个人以下:

<path fill="none" stroke="#78EADF" stroke-width="30" stroke-linecap="round" stroke-miterlimit="10" d="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2"/>复制代码

关于路径描边的各个属性值再也不赘述,注意标签中d=""部分,后面咱们的路径动画时要调用的就是这个路径。动画

path路径的参数由AI导出的SVG路径中的d生成。ui

2.路径动画<animateMotion>

关于路径动画最基础的语法简单到以下:url

<animateMotion path="" dur=""/>
<!--dur定义动画时间-->复制代码

其中path即为咱们在AI中绘制路径自动生成的d="" 所包含的定义路径曲线的部分。
如今,若是我定义一个最简单的圆形circle,加上路径动画属性,已经能够实现动画效果了,代码以下:spa

<circle fill="#F8B62D" r="20">
<animateMotion path="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2" dur="3s"/> 
</circle>复制代码

动画效果以下:设计

沿路径移动的圆形
沿路径移动的圆形

这里还有一个方法,就是咱们给蓝色路径定义一个id,而后路径动画来引用这个id,代码以下:

<!--road为咱们定义的路径id-->
<path id="road" fill="none" stroke="#78EADF" stroke-width="30" stroke-linecap="round" stroke-miterlimit="10" d="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2"/>
<circle fill="#F8B62D" r="20">
<animateMotion  dur="3s">
<mpath xlink:href="#road"/> <!--经过路径连接属性调用定义的路径-->
</animateMotion> 
</circle>复制代码

这两种方法都可,重点是第二种方法,后面将要揭秘。

3.任意图形的路径动画

看了上面的是否是感受so easy,但这确定不是咱们的需求,开始抛砖引玉,好比,我准备作一个沿路径奋力爬行的小瓢虫的动画。先准备素材,在AI中绘制一只小瓢虫,好比图层我命名beatles

绘制甲虫
绘制甲虫

而后获得一堆<g id="beatles">……</g>的SVG代码。
接下来就很简单了,用甲虫的图形来替换上面动画中的圆形,其余不变。获得代码以下:

<g id="beatles">
……<!--此处省略绘制甲虫的代码若干-->
<animateMotion path="M66.9,517 c0,0-37.8-194,125.1-161.9S427.6,371.5,350,205.7S439.3,23.4,544,62.2" dur="3s"/> 
</g>复制代码

期待已久的时刻来了,正常思路,咱们的小瓢虫能够沿着路径爬行了。各位看官先不要激动,此时,你看到的动画应该是这个样子的(为了方便观察,我把画布调整了大小,留出足够的空间)。

偏移了路线的小甲虫
偏移了路线的小甲虫

小甲虫,你要去哪里?你快回来。再看咱们的代码,没毛病,甲虫的位置明明就是摆在路径的起点上。不过咱们仍能发现的一个规律是:虽然小瓢虫跑偏了,但跑的姿式彷佛仍是对的。为何圆形没事,换个复杂的图形就不能够了呢?咱们上面圆形按照路径移动时,并无定义圆形的圆心位置(cx和cy值),仅定义了半径r。好了,接下来要放大招了,这是你之后制做SVG路径动画的关键。

4.任意图形的位置校订

先来看一句话: 定义了路径动画的图形会把路径的起点做为原点。读起来拗口且难懂,炒个栗子吧。我绘制的路径起点坐标为X=66.9,Y=517,对于了解SVG路径的小伙伴们都知道,其实就是path的起点M值。那对于甲虫来讲,(66.9,517)才是它坐标系的原点,而不是(0,0)。以下图所示,整个坐标系向右偏移了66.9px,向下偏移了517px。

偏移后的坐标系
偏移后的坐标系

因此最终的效果就是甲虫沿着偏移后的灰色路径移动。
知道了缘由就能够对症下药了。

4.1 方法1——把甲虫拉回它应该在的位置

既然知道偏移的值,再把它放回去,放回去的话就很简单了,咱们只要把甲虫移动到画布的左上角原点的位置(即x=0,y=0)

移动图形到原点处
移动图形到原点处

此时再导出SVG,除了甲虫图形代码替换,获得下面的效果:


小瓢虫强势回归!

4.2 方法2——使用SVG的defs元素

这个方法至关于方法1的扩展,你可使用defs来定义图形,use标签来调用,一样须要图形位于画布原点,代码以下:

<defs>
<g id="beatles">
……<!--此处为绘制瓢虫的代码-->
</g>
</defs>
<use xlink:href="#beatles" x="0" y="0">
<animateMotion  dur="3s">
<mpath xlink:href="#road"/> <!--方法2和方法1因为路径是同一条,因此都适合用调用路径的方法-->
</animateMotion>
</use>复制代码

用defs来定义图形的好处是,你可使用use标签在不一样位置重复调用这个图形,好比我下面说明运动速率时摆放的5只小甲虫。
由方法1和方法2咱们得出一个结论,图形绘制的时候无所谓位置,只要最后在画布的左上角原点就能够了

4.3 方法3——从新定义移动路径

上面的那个方法虽然能够实现正常路径运动,但实际中存在一个问题(个人动画播放时使用了无限循环,因此看不出)。当动画设置了延迟开始(eg. begin="2s")时,甲虫在动画开始前并非乖乖的待在起点A,而是移动后的位置,画布左上角,2s后动画开始播放,甲虫才回到A点。来看下面这种解决方案,从新定义图形的移动路径。
跟着我左右右手一个慢动做,右手左手慢动做重播……咱们用相同的方法来移动,不过,此次咱们移动的是路径,记得选择“复制”,或者干脆点,直接把起点拖到画布的原点。

移动路径
移动路径

而后为了方便区分,建议你给移动后的新路径区分一下描边方法。

新路径
新路径

好了,甲虫按兵不动,导出SVG时,复制后的路径那一堆代码咱们只须要d值,个人路径动画代码也就变成了下面的样子:

<animateMotion path="M0,0 c0,0-37.8-194,125.1-161.9s235.7,16.5,158.1-149.3s89.2-182.3,194-143.5" dur="3s"/>复制代码

如今,全部都恢复正常,咱们的小甲虫又能够乖乖的从A爬到B了,并且不管什么时候,起点和终点都是咱们预期值。(但这个方法有个很大的bug,后面再说)

做为有追求的设计师,这个动画效果是否是感受low到爆?首先,瓢虫移动速度不符合物理规律,匀速运动,其次,身体没有相应的转动,生硬不生动。好了,来,加上这几个属性,改善一下。

5. 运动速率的设定

先给animateMotion加上下面的代码:

calcMode="spline"  keySplines="" keyTimes="0;1"复制代码

calcMode属性定义动画的类型,一共四个属性值,其余不说了,"spline"要搭配后面的keySplineskeyTimes属性一块儿使用,以上代码的意思是宣告“我要来为所欲为的控制运动速率了!”
keySplines值的设定与CSS的贝塞尔曲线相同。
关于运动速率的贝塞尔曲线(说好了不提它,又来!)有个在线工具能够借助:cubic-bezier.com/

cubic-bezier工具
cubic-bezier工具

这里你能够自定义运动速率曲线并查看效果,不过若是不是须要一些特别的效果,建议使用如下几个固定值:
"慢-快-慢 ease":".25,.1,.25,1"
"线性 linear":"0,0,1,1"这个是默认值,能够不用定义。
"慢开始 ease-in":".42,0,1,1"
"慢结束 ease-out":"0,0,.58,1"
"慢-正常-慢 ease-in-out":".42,0,.58,1"
我作一个甲虫水平移动的动画,来对比一下这五种不一样的速率曲线的效果。

不一样运动速率曲线的甲虫
不一样运动速率曲线的甲虫

同时出发,但中间速度有差,异曲同工,又同时到达终点。
这里我搞了个事情出来,把速率曲线画成了下面这个样子:

任意绘制的曲线
任意绘制的曲线

因此个人keySplines=".28,1.89,.56,-1.32"。如今个人甲虫移动方式是这样的:

自定义移动速率曲线的甲虫
自定义移动速率曲线的甲虫

怎么样,是否是还算有趣。花样能够不少,自行尝试。

keyTimes值(0;1)是最简单的一种,没有对运动过程进行分割,若是你想玩出更深的套路,能够把路径截成好几段,而后定义不一样的keySplines值。再炒个栗子。
keyTimes="0;0.66;1" keySplines=".42,0,1,1;0,0,1,1;" 就是路径的前2/3,我但愿用ease-in函数定义速度,路径的后1/3线性速度,但在衔接处会抖一下,由于实在使用场景不多,因此keyTimes值就用最基础的就好。

6. 跟随路径曲度的旋转方向

这个简单,只有一句代码:rotate="auto",此时的路径动画已经实现的有模有样了。

跟随路径曲度的图形的旋转
跟随路径曲度的图形的旋转

前面提到过,4.3方法3——从新定义移动路径,有个bug的问题,就是这里,由于旋转方向是依据路径的走向,若是使用移动事后的路径,那旋转的效果简直不忍直视。
这里有一个悖论,方法1和方法2,正常旋转,但初始的甲虫的位置不能在起点,方法3,初始位置在起点,但不能正常旋转。(抓狂ing……)使用过程当中选哪一个选哪一个,好纠结。
好了,设计师们,不用纠结,选1和2,由于……
……
由于……
咱们能够用js定义动画开始的时间,哈哈,根本不须要begin属性。

好了,开始放能够复用的代码并注释,一切不能复用的SVG动画代码都是耍流氓!

<svg width="" height="">
<path id="road" fill="none" d=""/><!--路径所有由AI直接生成-->
<g>
……
<!--此处为若干图形代码-->
<animateMotion  dur=""  repeatCount="" rotate="auto"  calcMode="spline" keyTimes="0;1" keySplines="" ><mpath xlink:href="#road"/></animateMotion>
</g>
</svg>复制代码

嗯,over,就是介么简单。剩下的只是填空。
好比dur定义所有动画须要的时间,keySplines定义运动速率类型,repeatCount定义播放次数,上面都有一一解释。

那么利用路径动画,都能实现什么效果呢,来继续看:

7.1 路径动画功能扩展——伴随图形变化

如今我要实现一个小甲虫渐行渐远的效果,为了让效果看起来更逼真,我把底图描边路径从新作了一下,而后把keySplines="0,0,.58,1"即运动速率为ease-out慢结束,以下:

渐行渐远的甲虫
渐行渐远的甲虫

这个效果实现也不过再加一句缩放动画代码

<animateTransform dur="" attributeName="transform"  fill="freeze" type="scale" from="1 1" to="0.5 0.5" />复制代码

时间与路径动画保持一致,type="scale" from="1 1" to="0.5 0.5"表示宽高缩小到原来1/2。
你能够搞得很复杂,好比伴随甲虫腿的摆动,但涉及到复合动画,好麻烦,这也是我为何没有用一只带腿的甲虫的缘由,哈哈。

7.2 路径动画功能扩展——搭配描边动画+蒙版

结合描边动画和蒙版,咱们能够实现下面这种效果:

结合蒙版描边动画
结合蒙版描边动画

一架一路辛苦播撒小豆的飞机。
动画拆解:先绘制一个点状组成的螺旋线路径,而后给这个螺旋线加一个蒙版,把描边动画赋给蒙版,描边路径即为螺旋线路径,颜色为白色,至关于经过蒙版动态画一根白色螺旋线来实现点状螺旋线路径同步显示出来。小飞机就按咱们上面介绍过的的路径动画来定义。
感兴趣的话能够把下边的代码拿去复用:

<svg  width="600" height="600" >
<style>
@keyframes dash {
to {
stroke-dashoffset: 0;
}
}
#helix{
stroke-dasharray:2006;  /*2006为螺旋线的长度*/
stroke-dashoffset:2006; 
animation: dash 4s linear forwards;  /*蒙版动画的速率和时间与飞机路径动画保持一致*/
animation-delay:0.2s; /*为了让飞机稍微领先,设置了蒙版动画0.2秒的延迟*/
}
</style>
<mask id="helix">
<!--蒙版调用定义的描边动画helix,d=""包含部分为螺旋线的路径-->
<path fill="none" stroke="#fff" stroke-width="16" stroke-linecap="round" d=""/>
</mask>
<path mask="url(#helix)" id="road" fill="none" stroke="#78EADF" stroke-width="16" stroke-linecap="round" stroke-linejoin="round" stroke-dasharray="0,30" d=""/>
<g id="plane">
…<!--此处飞机代码若干-->
<animateMotion fill="freeze"   dur="4s"  rotate="auto"  calcMode="spline" keyTimes="0;1" keySplines="0,0,1,1" ><!--keySplines值的设定要与描边动画保持一致,若是上面animation定义了ease,则这里也要对应改为".25,.1,.25,1"-->
<mpath xlink:href="#road"/>
</animateMotion>
</g>
</svg>复制代码

知识点总结:
①动画的路径直接经过AI绘制后导出的SVG的d值得到。
②图形元素移动到画布原点后再生成对应的SVG代码。
③经过定义calcMode、keyTimes以及 keySplines来修改运动速度。
④定义rotate属性来实现跟随路径曲率的旋转效果。
⑤与其余动画的组合,须要多多的创意。

补充部分(更正):

CSS3有路径动画属性!有路径动画属性!有路径动画属性!在写这篇文章时,一直觉得路径动画是CSS3惟一不可取代SIML实现的动画,直到今天,我看到了这个,抑制不住的激动٩(๑>◡<๑)۶,我CSS3终于动画部分大统一了。

@keyframes move{              
0%{offset-distance:0%; }
100%{offset-distance:100%; }
 }
#move{
offset-path:path('');
animation:move 1s ease ;
}复制代码

是的,你没有看错,就是offset-pathoffset-distance两个属性。offset-path用于定义路径部分,offset-distance控制元素在路径上的运动距离。

至此,SVG+CSS3动画终于得以完美,全部动画部分均由CSS3来控制,SVG仅用来提供基础图形。由于不记得都在哪些文章中提到过路径动画了,因此无法一一更正,这是初始篇,因此但愿全部的阅读这篇文章的人都能看到,不要被我带坑里哦。

相关文章
相关标签/搜索