考虑一下以下的情景:
首先让我们先看一下下面这幅动图,图中George跑着穿过鸽子从而引起鸽子的展翅高飞。我们该如何模拟这种效果呢?
仔细观察一下这些鸽子,它们数量不是很多,但是它们都是单独起飞。
我们采用错开动画的方式来重建这样的效果,而不是一次就控制一组动画。随着每一个项目动画延迟时间的增加,它们表现的就像是一个个独立的个体,但仍然会作为一个整体正确的移动。这样的结果感觉更加迷人且真实。
我最近刚发布的Isotope v3项目就使用了这种方法:
尽管每一项的过渡很好设置,但是管理却很困难。在不同的时间间隔运行动画会变得非常复杂。因此,下面就让我们来讨论如何更有效的错开每一项的过渡。
在示例中我们使用了一个简单的动画:水平移动一组项目。每一项都有一个CSS过渡:transform 0.4s
,他们通过切换.is-moved
类来移动。以下是所有项目一起移动的第一个示例:
setTimeout
我们可以使用setTimeout
来错开切换过渡。在JavaScript中,setTimeout
将会在一个延迟之后才开始过渡。
这个效果看起来已经很棒了。不过我还是想微调一下动画,我希望每一项能不重叠移动。也就是说如果是向右移动,最先开始移动的是右边的项目;如果是向左移动,最先开始移动的应该是左边的项目。所以我们就需要在向右移动的时候反转一下setTimeout
的延迟。
看上去还不赖,那么我们对这个动画进行一些测试:如果在动画过程中切换移动方向会发生什么呢?这种边缘情况经常会被忽视。任何新手开发人员都可以添加动画。但是,如果你重视你的用户,那么一旦用户有所行动你的动画就应该立即反应。动画不应该妨碍用户的操作。
在过渡的过程中点击按钮看看会发生什么:
看上去起作用了,每一项都在他们应该停止的地方停止了。但是我不喜欢它们现在的这种表现形式。看上去好像每一项都很困惑。同时我们也在没有反转setTimeout
延迟的示例上试一下:
正向/反向过渡继续通过了所有项目。这种结果并不是我们想要的。用户已经改变了他们行动,但是动画仍在发生。
transition-delay
另外我们也可以尝试一些其他的方法。既然我们已经使用了CSS的transition
,那么自然就想到可以使用transition-delay
。以下的示例使用JavaScript来设置增量的transition-delay
(当然你也可以使用CSS预处理逻辑来实现)。对于所有项目而言,过渡切换是同样的时间,但是延迟时间根据transition-delay
的值而不一样。
我们也可以颠倒一下延迟来到达和setTimeout
示例中同样的左右移动的效果:
当在过渡过程中点击按钮,那么正向/反向过渡会立刻停止:
这个方法虽然可行,但仍不是我们理想中的效果。
基于帧的动画
另外还有一种方法可以尝试:基于帧的动画。使用requestAnimationFrame
,我们就可以在每一个过渡被触发时对它进行控制。
这个效果简直完美!在过渡过程中切换移动方向,原来的过渡会立刻停止且反向过渡,没有延迟也没有多余的过渡动作。但是我们只能牺牲复杂度来达到这样完美的效果。这个示例需要两倍的JavaScript代码,其中还带有一个每一帧都需要运行的动画循环。
总结
所以如果你需要错开动画,你有这些选择来实现你想要的效果:
setTimeout
可以,但是很难取消。transition-delay
也可以,但是可能会有延迟。requestAnimationFrame
可以,但是需要更多的JavaScript。
除此之外,还有很多其他选择:CSS的animations
,jQuery的.animate()
,GreenSock, D3,等等。这些方案都可以用来错开动画,但是我会建议你去研究一下当用户在动画过程中有所动作时,这些方案会如何反应。
在Isotope中,我使用了transition-delay
。它不用太过复杂就能提供最佳的控制。
本文根据@David DeSandro的《Staggering Animations》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://css-tricks.com/staggering-animations。
如需转载,烦请注明出处:http://www.w3cplus.com/animation/staggering-animations.html