最近通过一些微信公众号了解到现在SVG还可以通过各种标签实现动画,如果脑洞够大,动画可以非常fancy。于是乎还是手痒简单学习了一下,在此记录一下SVG动画相关的一些标签和属性备忘。
首先MDN的这个SVG文档还是很全面的,随时忘了就去这里查一下也方便。
animate
说到动画,自然先用到的就是animate 标签了,该标签用于控制SVG在具体某个属性上变化的动画,比如宽度、高度、透明度、圆心的位置等等。
指定控制目标
animate 标签默认是控制其直接父标签的,因此加在一个<g> 标签中就是控制该组中所有的SVG对象,该<g> 标签的初始状态也就是很多属性的默认值。
不过也有xlink:href 属性,可以指明要控制的标签。这样也方便把所有animate 标签集中管理:
<animate xlink:href="#cool_shape" ...=""></animate>
...
<rect id="cool_shape" ...="" />
应注意若使用xlink:href 属性指明动画目标,还是要求对应的对象和animate 标签在同一个svg 中。
设置动画属性
attributeName
既然animate 控制的是在某个属性值上变化的动画,就要先通过attributeName 指定变化的元素属性名称。主要也就两类:
- 可以是元素直接暴露的SVG属性,比如
stroke-width (描边宽度); - 可以是CSS属性,比如
opacity (透明度);
attributeType
attributeType 用于指定设置的属性对应的类型,可选值有CSS | XML | auto ,默认值为auto ,即自动判断。SVG和CSS中确实有很多同名属性,不过目前使用过程中没有设置过attributeType ,让浏览器自动判断还没出过问题。
设置属性值具体变化
设置好了要变换的属性,就要设置该属性值的变化节点来定义动画。
from/to/by
最简单的设置属性值的变化就是通过这三个属性进行:
from : 表示动画开始时的属性值,默认为None,会根据控制目标开始时的状态获取;to : 表示动画结束时的属性值,默认为None;by : 表示动画结束时,相对于开始时的差值,若通过to 定义了结束时的绝对属性值,则会忽视by 。默认为None;
values
一个动画往往是多段动画的组合,若只能定义起始状态就要重复组合多个动画,自然比较麻烦。此时可以通过values 定义一系列属性值的变化,将在同一属性值上变动的多段动画组合起来,属性值之间通过; 分割。设置了values 则忽视from/to/by 这些单一起始位点的定义。
使用CSS定义动画,可以通过设置animation-direction:alternate 使动画可以往复运动。animate 标签没有类似的属性直接定义往复运动,不过也可以通过values 属性,设置结束值等于起始值,也一样可以实现往复运动的效果。比如经典的呼吸灯效果,就是让透明度在0到1之间往复变化嘛:
<animate attributeName='opacity' dur='2s' values="1;0;1" repeatCount="indefinite"/>
additive
默认情况下additive="replace" ,也就是from/to/by 设置的值都是绝对值。而当设置additive="sum" 后,from/to/by 设置的值就是相对于动画开始前对象的值。个人认为设置绝对值相对更加清晰,目前较少设置该属性。
accumulate
默认情况下accumulate=none ,即动画重复都是重头开始的。而若设置accumulate="sum" ,则通过repeatCount 设置的动画重复次数,每一次重复是基于上一次的结果开始的。如设置圆心位置向右移动10px,重复3次,若设置accumulate="sum" ,动画总体效果是圆心位置向右移动了30px。目前常用于大规模复制(而不是重复)同样的动画,如以同样的步幅向一个方向前进。
设置动画时间和循环方式
dur
正如其名,该属性就定义了动画的持续时间(duration)。除了常用的时间,如1s,也可以定义为indefinite ,即无限时间。默认值即为indefinite ,因此SVG动画常常需要明确指定该属性。
keyTimes
若通过values 定义了一系列属性值的变化,则还可以通过keyTimes 定义一个时间节点的列表,来定义每个属性值节点对应的时间。单位是dur 定义时长的百分比,因此值为0-1之间的小数,第一个值一定是0,最后一个一定是1。值之间通过; 分割,列表长度与values 长度一致。不定义keyTimes 则默认在values 各个属性值变化之间平均分配dur 持续时间。
begin/end
begin 确定动画开始的时刻,可以是一个; 分割的列表,表示会分别在这些时刻开始动画。具体的值有以下几种方式:
- 相对于页面完成加载后的时间,如0.1s;
- 发生在执行动画的svg对象上的事件,最常用
click ; - 另一个动画的某个时间节点,如某个
id="test" 的动画结束则可用test.end 表示; - 上述方式还可以组合使用,如
click+1s 表示点击后延迟1s开始;
end 则确定动画结束的时刻。如果是列表,则长度必须与begin 一致,值的定义方式也与begin 一样。注意end 确定的是svg对象退出动画状态的时间。若end 相对begin 的时间长度小于dur ,则动画会提前停止。反之动画效果跟没有设置end 一样,但svg对象的状态却仍然是动画中,直到end 设置的时间。
fill
fill 表示在动画结束后,是否保持在结束状态。可选值remove|freeze :remove 表示动画结束后,恢复到动画开始时的状态,默认为该值;freeze 则表示动画结束后,则保持在结束状态,也就是下一个动画的起始状态。
repeatCount
repeatCount 设置了动画重复的次数,也可以设置为indefinite 表示一直不断循环播放。
注意若begin 为一个列表,动画就会多次开始,但又设置了repeatCount ,动画还会在每次开始时都重复同样的次数。时间线相对较混淆,最好不要混合使用。
restart
restart 设置动画何时可以重新开始,有如下几种具体设置:
always : 默认值,表示动画可以在任何时候重新开始,包括上一次动画还没结束就可以重头再来;whenNotActive : 表示动画仅可以在动画结束时才可以重新开始;never : 表示动画不可以重新开始,除非刷新整个页面。但并不影响repeatCount ;
repeatDur
repeatDur 通过时间限制动画的重复次数,设置的值表示动画可以持续的总时间,也可以设置为indefinite ,表示不限制动画重复的时长。repeatDur 和repeatCount 二者如果都设置了,则取可以重复的最小值。比如一个时长1s的动画,repeatCount="5" 而repeatDur="3s" ,则只会重复3次。repeatDur 不是dur 的整数倍那也就在中间截止。
min/max
与repeatDur 类似,min/max 两个属性则限制了动画最短/最长的运行时间。个人一般更愿意通过dur/begin/repeatCount 等控制时间,不常用这些属性来提前停止动画,或使SVG元件即使动画结束但仍保持在动画状态。
calcMode(插值计算方法)
由于是动画,属性值相对时间是连续变化的。而之前所描述的属性均只设置了属性值和时间的节点,节点间属性值随时间变化的方式就要通过calcMode 来定义,有如下几种方式:
animateTransform
只用animate 控制某些属性值变化的动画自然还是不够的,animateTransform 可以用来控制SVG的位移、旋转、缩放等的变化动画。其中属性与animate 基本相同,其中attributeName="transform" 固定不变,type 决定具体的transform方式,属性值values /from /to 则为transform方式对应的参数值,如:
- 平移:
translate(x,y=0) ,分别向x和y轴移动指定距离,y可选,默认为0; - 缩放:
scale(x,y=x) ,分别在x轴和y轴放大指定倍数,y可选,默认与x相同; - 旋转:
rotate(ang,x=0,y=0) ,按照指定点(x,y)顺时针旋转ang角度,默认按照整个svg的原点旋转; - 斜切:
skewX(ang) ,沿x轴斜切ang角度;skewY(ang) ,沿y轴斜切ang角度;
举例:
<animateTransform attributeName="transform" type="rotate" from="0 60 70" to="360 60 70" dur="10s" repeatCount="indefinite"/>
<animateTransform attributeName="transform" begin="0.1" dur="2s" repeatCount="indefinite" type="translate" values="0;10;0"></animateTransform>
<animateTransform attributeName="transform" begin="0.1" dur="0.2s" type="scale" values="5;1" fill="freeze" restart="never"></animateTransform>
值得注意的是,各种transform变化默认相对图像原点进行。而常常想要每个对象相对自身的中心进行变化,需要加上下列css样式:
transform-box: fill-box;
transform-origin: center;
不过这些css样式目前还在实验阶段,对一些老旧的浏览器兼容性不好。
animateMotion
path / mpath
animateMotion 标签控制SVG对象在指定的路径上移动。其中的path 属性就定义了移动路径:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<path fill="none" stroke="lightgrey"
d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
<circle r="5" fill="red">
<animateMotion dur="10s" repeatCount="indefinite"
path="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
</circle>
</svg>
如上例,移动路径常常复用的一个已经绘制出来的路径,因此可以在animateMotion 标签中使用mpath 标签来链接到已有的路径:
<svg viewBox="0 0 200 100" xmlns="http://www.w3.org/2000/svg">
<path id="movePath" fill="none" stroke="lightgrey"
d="M20,50 C20,-50 180,150 180,50 C180-50 20,150 20,50 z" />
<circle r="5" fill="red">
<animateMotion dur="10s" repeatCount="indefinite">
<mpath xlink:href="#movePath"/>
</animateMotion>
</circle>
</svg>
值得注意的是,运动路径与运动对象的位置是相对的,即运动路径的原点就是运动目标的原点。因此若运动路径和运动目标画在同一张图上,那么运动开始前运动目标的中心最好就在整张图像的原点,如上述几个例子。这样运动开始时,目标才会真正移动到运动路径上开始运动。或者反过来将运动路径从原点开始绘制,之后运动目标才可以在它所在的位置上按照运动路径的形状开始运动,不过这种情况下运动路径一般就不方便绘制出来展示。
keyPoints
keyPoints 与keyTimes 配合,可以用于精细控制对象在路径上不同部分的速度。如keyPoints="0;0.5;1" keyTimes="0;0.15;1" ,表示运动完路径的前半部分花费15%的时间,运动后半部分花费85%的时间。
rotate
rotate 用于控制移动对象沿路劲运动时的朝向,默认为0,即移动时朝向始终不变。可选auto 和auto-reverse ,使对象的朝向可以自动朝向或反向移动路径。
|