SMIL不是指「水蜜梨」,而是Synchronized Multimedia Integration Language(同步多媒体集成语言)的首字母缩写简称,是有标准的。本文所要介绍的SVG动画就是基于这种语言。
SMIL允许你做下面这些事情:
注意到“沿着运动路径运动”这一条没?前面的三条CSS3都是可以有所担当的,最后这一条,呵呵,CSS3只能蹲在墙角画圈圈了!(更正与2020-08-08 目前CSS offset
属性也可以让元素沿着额不规则路径运动)
SVG的动画元素是和SMIL开发组合作开发的。SMIL开发组和SVG开发组合作开发了SMIL动画规范,在规范中制定了一个基本的XML动画特征集合。SVG吸收了SMIL动画规范当中的动画优点,并提供了一些SVG继承实现。
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马text>
<animateTransform attributeName="transform" begin="0s" dur="10s" type="rotate" from="0 160 160" to="360 160 160" repeatCount="indefinite"/>
g>
svg>
需要注意的是,IE浏览器(包括IE11)是不支持的
三秒后,马 自04-动移动 x 60px 的位置:
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">
马
<set attributeName="x" attributeType="XML" to="60" begin="3s" />
text>
g>
svg>
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">
马
<animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
text>
g>
svg>
一看就知道是颜色动画。不过,animate可以实现其功能与效果,因此,此属性已经被废弃。
这里的 transform
变 换 与 CSS3 的 transform
变换,基本类似,只不过通过标签的方式进行设置:
<svg width="320" height="320" xmlns="http://www.w3.org/2000/svg">
<g>
<text font-family="microsoft yahei" font-size="80" y="100" x="100">马text>
<animateTransform attributeName="transform" begin="0s" dur="3s" type="scale" from="1" to="1.5" repeatCount="indefinite"/>
g>
svg>
animateMotion
元素可以让 SVG 各种图形沿着特定的 path
路径运动:
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
<animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" repeatCount="indefinite"/>
text>
<path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
svg>
不过上面这个马走得有点假,怎么马儿一直都是水平的啊,这不符合物理学定律,是不科学的。我们可以小小处理下,让表现更真实:
<svg width="360" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="40" x="0" y="0" fill="#cd0000">马
<animateMotion path="M10,80 q100,120 120,20 q140,-50 160,0" begin="0s" dur="3s" rotate="auto" repeatCount="indefinite"/>
text>
<path d="M10,80 q100,120 120,20 q140,-50 160,0" stroke="#cd0000" stroke-width="2" fill="none" />
svg>
实际制作时候的动画,不可能总是一个属性修改。比方说,位置和透明度同时变化,只需要设置多个动画元素即可:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate attributeName="x" from="160" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
<animate attributeName="opacity" from="1" to="0" begin="0s" dur="3s" repeatCount="indefinite" />
text>
svg>
attributeName:要变化的元素属性名称,跟 CSS3 设置 transition-property 过渡一致,不过位移不是 translate 了,而是 x 和 y
attributeType = “CSS | XML | auto”:attributeType
支持三个固定参数,CSS
/XML
/auto
. 用来表明 attributeName
属性值的列表。
x
, y
以及 transform
就属于XML
, opacity
就属于CSS
. auto
为默认值attributeType
值,直接让浏览器自己去判断,几乎无差错。不知大家有没有和我一样的疑问:“既然浏览器酱可以自己判断属性类别,那这个属性还有什么意义吗?”我琢磨着,可能某些属性,XML能其作用,CSS也能其作用,例如
font-size
, 此时就需要明确下归属。
from, to, by, values
from
, to
, by
, values
虽然属于一个家族,但是相互之间还是有制约关系的。有以下一些规则:
如果动画的起始值与元素的默认值是一样的,from
参数可以省略。
(不考虑values
)to
,by
两个参数至少需要有一个出现。否则动画效果没有。to
表示绝对值,by
表示相对值。拿位移距离,如果 from
是100
, to
值为160
则表示移动到 160
这个位置,但是,如果 by
值是 160
,则表示移动到 100+160=260
这个位置。
如果to
,by
同时出现,则 by
打酱油,只识别 to
如果to
,by
,values
都没设置,自然没动画效果。如果任意(包括from
)一个属性的值不合法,规范上说是没有动画效果。但是,据我测试,FireFox 浏览器确实如此,但是Chrome特意做了写容错处理。例如,本来是数值的属性,写了个诸如 a
这个不合法的值,其会当作 0
来处理,动画效果依然存在。
values
可以是一个值或多值。根据我在Chrome浏览器下的测试,是一个值的时候是没有动画效果。多值时候有动画效果。当 values
值设置并能识别时候,from
, to
, by
的值都会被忽略。
那 values
属性是干什么的呢?别看名字挺大众的,其还是有些功力的。
我们实现动画,不可能就是单纯的从a位置到b位置,有时候,需要去c位置过渡下。此时,实际上有3个动画关键点。而 from
, to
/by
只能驾驭两个,此时就是 values
大显身手的时候了,例如下面这个聪明的马儿来回跑的效果:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="150" x="160">
马
<animate attributeName="x" values="160;40;160" dur="3s" repeatCount="indefinite" />
text>
svg>
repeatCount, repeatDur:
repeatCount:表示动画执行次数,可以是合法数值或者 indefinite
repeatDur:定义重复动画的总时间。可以是普通时间值或者 indefinite
例如这个:
<animate attributeName="x" to="60" dur="3s" repeatCount="indefinite" repeatDur="10s" />
动画只执行完整 3
个 + 一个 1/3
个动画。因为 repeat 总时间就 10s
而已。
dur:常规时间值 | "indefinite"
,动画持续时间,设置 indefinite 相当于动画压根不执行
fill:表示动画间隙的填充方式,支持参数有:freeze
| remove
。其中 remove
是默认值,表示动画结束直接回到开始的地方。freeze
“冻结”表示动画结束后像是被冻住了,元素保持了动画结束之后的状态。
例如,beigin="3s;5s"
表示的是 3s
之后动画走一下,6s
时候动画再走一下(如果之前动画没走完,会立即停止从头开始)。所以,如果一次动画时间为 3s
, 即 dur="3s"
,同时没有 repeatCount
属性时候,我们可以看到动画似乎连续执行了2
次。
时间值:支持 “h” | “min” | “s” | “ms”,不添加单位默认为 s
begin
的单值除了普通 value,还有下面这些类别的 value:
offset-value:
syncbase-value:基于同步确定的值吗,语法为:[元素的id].begin/end +/- 时间值
借用其他元素的 begin 值再加加减减,这个可以准确实现两个独立元素的动画级联效果:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate id="x" attributeName="x" to="60" begin="0s" dur="3s" fill="freeze" />
<animate attributeName="y" to="100" begin="x.end" dur="3s" fill="freeze" />
text>
svg>
于是,实现了一个马儿折线跑的效果,先横向移动,再无缝纵向移动:
当然,我们还可以增加一些偏移值,例如 begin="x.end-1s"
, 就表示 id
为 x
的元素动画结束前一秒开始纵向移动
event-value:表示与事件相关联的值。类似于 PowerPoint 动画的“点击执行该动画。语法是:[元素的id].[事件类型] +/- 时间值
举个例子,点击下图的圆圈圈,马儿它就会自己跑:
<svg id="svg" width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<circle id="circle" cx="100" cy="100" r="50">circle>
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate attributeName="x" to="60" begin="circle.click" dur="3s" />
text>
svg>
马 主要注意的是,这类与事件关联的SVG需要内联在页面中,否则 click
什么的都是徒劳。
repeat-value:重复多少次之后做什么,语法为:[元素的id].repeat(整数) +/- 时间值
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate id="x" attributeName="x" to="60" begin="0s" dur="3s" repeatCount="indefinite" />
<animate attributeName="y" to="100" begin="x.repeat(2)" dur="3s" fill="freeze" />
text>
svg>
begin="x.repeat(2)"
指 id
为 x
的元素的动画重复 2
次后执行:
accessKey-value:定义快捷键,即按下某个按键动画开始。语法为:accessKey("character")
. character
表示快捷键所在的字符
举个例子,按下s
键动画走起。SVG代码如下:
<svg width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate attributeName="x" to="60" begin="accessKey(s)" dur="3s" repeatCount="indefinite" />
text>
svg>
按下键盘上的字母"s"
, 理论上动画就会执行。但是,据我测试,我的Chrome浏览器(版本36)上是没有效果的,FireFox浏览器效果杠杠的!所以,如果您的浏览器没有效果,但是手上有火狐,可以复制下面这个地址去FireFox浏览器下感受下:http://www.zhangxinxu.com/study/201408/horse-accesskey-value.svg
wallclock-sync-value:指真实世界的时钟时间定义。时间语法是基于在ISO8601中定义的语法。例如1997-07-16T19:20:30.45+01:00
indefinite:表示“无限等待”,需要使用 beginElement()
方法触发或者指向该动画元素的超链接(SVG中的a
元素):
js 代码触发如下:
<svg id="svg" width="320" height="200" xmlns="http://www.w3.org/2000/svg">
<text font-family="microsoft yahei" font-size="120" y="160" x="160">马
<animate attributeName="x" to="60" begin="indefinite" dur="3s" />
text>
svg>
<script>
var animate = document.getElementsByTagName("animate")[0];
if (animate) {
document.getElementById("svg").onclick = function() {
animate.beginElement();
};
}
script>
a 标签超链接触发如下:
<svg width="320" height="200" font-family="microsoft yahei" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<text font-size="120" y="160" x="160">马
<animate id="animate" attributeName="x" to="60" begin="indefinite" dur="3s" repeatCount="indefinite" />
text>
<a xlink:href="#animate">
<text x="10" y="20" fill="#cd0000" font-size="30">点击我text>
a>
svg>
If no begin is specified, the default value is “0” – the animation begins when the document begins. If there is any error in the argument value syntax for begin, the default value for begin will be used.
意思是,没有 begin
或者 begin
参数解析异常,都当作 0
处理。
calcMode, keyTimes, keySplines:这几个参数是控制动画先快还是先慢类似这样作用的
discrete
| linear
| paced
| spline
. 中文意思分别是:“离散”|“线性”|“踏步”|“样条”。
from
值直接跳到 to
值calcMode
默认值。动画从头到尾的速率都是一致的。position
, width
, height
等)。如果 paced
指定,任何keyTimes
或 keySplines
值都会打酱油spline
点的定义在 keyTimes
属性中,每个时间间隔控制点由 keySplines
定义。
:跟上面提到的
类似,都是分号分隔一组值。前面提到过 values
也是多值,这里有一些约定的规则:
keyTimes
值的数目要和 values
一致,如果是 from/to/by
动画,keyTimes
就必须有两个值。linear
和 spline
动画,第一个数字要是0
, 最后一个是1
。 最后,每个连续的时间值必须比它前面的值大或者相等。paced
模式下,keyTimes
会被忽略;keyTimes
定义错误,也会被忽略;dur
为indefinite
也会被忽略。
:keySplines
表示的是与 keyTimes
相关联的一组贝塞尔控制点(默认0 0 1 1
)
x1 y1 x2 y2
.spline
时候这个参数才有用,也是分号分隔,值范围0~1
,总是比 keyTimes
少一个值。keySplines
值不合法或个数不对,是没有动画效果的。如下4个SVG,只展示重要部分代码:
<animate attributeName="x" dur="5s" values="0; 20; 160" calcMode="linear" />
<animate attributeName="x" dur="5s" values="0; 20; 160" calcMode="paced"/>
<animate attributeName="x" dur="5s" values="0; 80; 160" keyTimes="0; .8; 1" calcMode="linear"/>
<animate attributeName="x" dur="5s" values="0; 80; 160" keyTimes="0; .8; 1" calcMode="spline" keySplines=".5 0 .5 1; 0 0 1 1" />
可以看到到4匹马上半途中你追我赶的经常场面:
拿最后一个SVG说事吧,实际上就是 values
, keyTimes
, keySplines
三个人之间事情。
values
确定动画的关键位置,keyTimes
确定到这个关键点需要的时间keySplines
确定的是每个时间点段之间的贝塞尔曲线,也就是具体的缓动表现我们平时 CSS3 写的 transition
动画效果,也是这么回事,这是 values
值就两个,所以,keyTimes
只能 是0-1
, 贝塞尔曲线就只有一个,要不 ease
, 要不 linear
等。
accumulate, additive:
none
| sum
. 默认值 是none
. 如果值是 sum
表示动画结束时候的位置作为下次动画的起始位置。replace
| sum
. 默认值是 replace
. 如果值是 sum
表示动画的基础知识会附加到其他低优先级的动画上举两个例子,下面是例子1:
<img ...>
<animateMotion begin="0" dur="5s" path="[some path]" additive="sum" fill="freeze" />
<animateMotion begin="5s" dur="5s" path="[some path]" additive="sum" fill="freeze" />
<animateMotion begin="10s" dur="5s" path="[some path]" additive="sum" fill="freeze" />
img>
这里轮到第二个动画的时候,路径是从第一个动画路径结束地方开始的,于是,3个动画完美无缝连接起来了。
例子2:
<animateTransform attributeName="transform" type="scale" from="1" to="3" dur="10s" repeatCount="indefinite" additive="sum"/>
<animateTransform attributeName="transform" type="rotate" from="0 30 20" to="360 30 20" dur="10s" fill="freeze" repeatCount="indefinite" additive="sum"/>;
这里,两个动画同时都是 transform
,都要使用一个 type
属性,好在这个例子 additive="sum"
是累加的而不是 replace
替换。于是,我们就可以是实现一边旋转一边放大的效果:
restart = always | whenNotActive | never:
always
是默认值,表示总是,也就是点一次圈圈,马儿跑一下whenNotActive
表示动画正在进行的时候,是不能重启动画的never
表示动画只执行一次min, max:表示动画执行最短和最长时间。支持参数为时间值和"media"
(媒介元素有效), max
还支持 indefinite
SVG animation 中是有内置的API可以暂停和启动动画的,语法为:
tips:不能够对使用 img、object、iframe 的标签使用,只能针对内嵌的标签
// svg 指当前 svg DOM 元素
// 暂停
svg.pauseAnimations();
// 重启动
svg.unpauseAnimations()
参考: