前端开发者学堂 - fedev.cn

惊艳的动画

发布于 若水

考虑一下以下的情景:

首先让我们先看一下下面这幅动图,图中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