SMIL动画不死:SVG中的高级动画技术详解

本文深入探讨SMIL在SVG动画中的应用,包括animate、animateTransform和animateMotion元素的使用,通过实际案例展示如何实现复杂动画效果和同步控制。

Smashing Animations Part 3: SMIL不死,宝贝,SMIL不死

虽然CSS动画有很多方式可以让设计变得生动,但在SVG中添加简单的SMIL(同步多媒体集成语言)动画可以让它们做得更多。Andy Clarke解释了SVG中的SMIL动画在CSS力所不及的地方如何发挥作用。

SMIL规范由W3C于1998年推出,用于同步多媒体。这远在CSS动画或基于JavaScript的动画库出现之前。它内置在SVG 1.1中,这就是为什么我们今天仍然可以在那里使用它。

现在,你可能听说过SMIL已经死了。然而,自从谷歌大约十年前撤销弃用该技术的决定以来,它一直活跃且良好。对于希望使用简单、语义化方式为设计添加动画的设计师和开发者来说,它仍然是一个绝佳的选择。

构建动画

<animate>只是SVG中几种动画元素之一。与attributeName值一起,它可以基于元素的一个或多个属性实现动画。

大多数动画解释从移动一个基本形状开始,比如这个令人兴奋的圆:

1
2
3
4
5
6
7
<circle
  r="50"
  cx="50" 
  cy="50" 
  fill="#062326" 
  opacity="1"
/>

使用这个attributeName属性,我可以定义要动画化这个圆的哪个属性,在这个例子中,是它的cx(x轴中心点)位置:

1
2
3
<circle ... >
  <animate attributename="cx"></animate>
</circle>

单独使用这个什么都不会做,直到我定义另外三个值。from关键字指定圆的初始位置,to指定其最终位置,以及这两个位置之间的duration(持续时间):

1
2
3
4
5
6
7
8
<circle ... >
  <animate 
  attributename="cx"
  from="50" 
  to="500"
  dur="1s">
  </animate>
</circle>

如果我想要更精确的控制,可以用分号分隔的一组值替换fromto

1
2
3
4
5
6
7
<circle ... >
  <animate 
  attributename="cx"
  values="50; 250; 500; 250;"
  dur="1s">
  </animate>
</circle>

最后,我可以定义动画重复多少次(repeatcount),甚至重复应该在什么时间段后停止(repeatdur):

1
2
3
4
5
6
7
8
<circle ... >
  <animate 
  attributename="cx"
  values="50; 250; 500; 250;"
  dur="1s"
  repeatcount="indefinite"
  repeatdur="180s">
</circle>

animateTransform

如果<animate>控制属性,那么animateTransform则动画化变换,包括旋转、缩放、倾斜和平移。它通过改变transform属性的值来工作,比如这个平移:

1
<path transform="translate(0,0)"/>

然后,动画的工作方式与<animate>相同,添加一个attributename并指定变换类型,在这个例子中是旋转:

1
2
3
4
<animatetransform 
  attributename="transform"
  type="rotate">
</animatetransform>

我可以使用fromtovalues属性来定义元素如何变换。

  • 缩放使用x和y值(.5, 1)
  • 旋转使用度数(0-360)加上可选的x和y(360, 0, 0)
  • 平移也使用x和y值(50, 100)
  • 倾斜也使用x和y值(50, 100)

开始和停止

到目前为止,每个动画都在页面加载后立即开始。但有方法不仅可以延迟动画的开始,还可以使用begin属性精确定义它开始的位置:

1
2
3
4
5
6
7
8
9
<animatetransform
  attributename="transform"
  type="translate"
  from="0 0"
  to="750 0"
  dur=".25s"
  begin="2s"
  fill="freeze"
/>

或者,我可以在用户点击箭头时让观看者射击:

1
2
3
<animatetransform
  ...
  begin="click"
1
2
3
4
5
6
7
8

我可以结合点击事件和延迟,完全不需要JavaScript,只需一点SMIL:

```svg
<animatetransform
  ...
  begin="click + .5s"
/>

同步动画

动画可以在页面加载时开始,在指定时间后开始,或者点击时开始。通过给它们命名,它们还可以与其他动画同步。

我想让Yogi先进入画面以建立 anticipation,在其他动画开始前有一个短暂的停顿,同步到他到达的时刻。首先,我给Yogi的平移动画添加一个ID:

1
2
3
4
5
<animateTransform
  id="yogi"
  type="translate"
  ...
/>

注意:出于某种原因,我无法解释为什么Firefox在ID包含连字符时不会开始动画。这并不比普通浏览器聪明,但用下划线替换连字符可以解决这个问题。

然后,我给他的旋转动画应用一个begin,在#yogi动画结束后半秒开始播放:

1
2
3
4
5
<animateTransform
  type="rotate"
  begin="yogi.end + .5s"
  ...
/>

沿运动路径动画

到目前为止,这些标题卡中的所有动画都是上下左右或某种组合。但SVG中的SMIL还有一个方面可以为动画增加一个额外的维度:使用animateMotion元素沿运动路径动画。

animateMotion接受与animateanimateTransform相同的所有属性和值,但增加了几个用于更精细控制方向和时间。animateMotion使用path属性使元素能够沿运动路径移动。它还使用d值作为坐标数据,与任何常规路径相同。

1
2
3
4
5
6
7
<g>
  <animateMotion
    dur="2s"
    path="..."
  >
  </animateMotion>
</g>

或者,我可以添加一个path元素,保持其可见,或通过将其放在defs元素内来防止其被渲染:

1
2
3
<defs>
  <path id="yogi" d="..." />
</defs>

然后我可以在我的animateMotion中使用mpath元素引用它:

1
2
3
4
<animateMotion
  ...
  <mpath href="#yogi" />
</animateMotion>

keyPoints属性使我能够指定运动路径上的点,然后调整Yogi在它们之间花费的持续时间。为了简单起见,我定义了0到1之间的五个点:

1
2
3
4
5
<animateMotion
  ...
  keyPoints="0; .35; .5; .65; 1;"
>
</animateMotion>

然后我添加相同数量的keyTimes值,用分号分隔,以控制这个动画的节奏:

1
2
3
4
5
<animateMotion
  ...
  keyTimes="0; .1; .5; .95; 1;"
>
</animateMotion>

SMIL不死,宝贝。SMIL不死

凭借其控制变换、动画复杂运动路径和同步多个动画的能力,SVG中的SMIL动画仍然是强大的工具。它们可以在不需要框架或不依赖JavaScript的情况下让设计变得生动。它很紧凑,这使它非常适合小的SVG效果。

SMIL包括begin属性,这使得链接动画比使用CSS直观得多。此外,SMIL存在于SVG文件内部,使其非常适合随资源传播的动画。因此,虽然SMIL按今天的标准并不现代,可能有点小众,但它仍然可以是神奇的。

不要让SMIL"已死"的误解阻止你使用这个神奇的工具。

“谷歌几乎十年前撤销了弃用SMIL的决定,因此对于希望使用简单、语义化方式为设计添加动画的设计师和开发者来说,它仍然是一个绝佳的选择。”

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计