SVG SMIL动画技术深度解析:从基础到高级应用

本文详细介绍了SVG SMIL动画技术的核心概念和实际应用,包括animate、animateTransform、animateMotion等元素的用法,以及如何实现复杂动画序列和路径动画,为设计师和开发者提供了强大的动画实现方案。

粉碎动画第三部分: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指定最终位置,dur指定这两个位置之间的持续时间:

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
4
<animatetransform
  ...
  begin="click"
/>

我还可以结合点击事件和延迟,所有这些都不需要JavaScript,只需要一些SMIL:

1
2
3
4
<animatetransform
  ...
  begin="click + .5s"
/>

同步动画

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

我想让Yogi先进入画面以制造期待感,在其他动画开始前有一个短暂的停顿,同步到他到达的时刻。首先,我给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并未消亡,它依然强大

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

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

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

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

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