延迟关键帧动画的新方法

Avatar of Eric Johnson
Eric Johnson

DigitalOcean 为您旅程的每个阶段提供云产品。立即开始使用 200 美元的免费额度!

如果您曾经想在 CSS @keyframes 动画的每次迭代之间添加一个暂停,您可能已经很沮丧地发现 CSS 中没有内置的方法来做到这一点。当然,我们可以使用 animation-delay 延迟一组 @keyframes开始,但是没有办法在关键帧的第一次迭代和后续每次运行之间添加时间。

当我想要调整 这个流星动画 以用作太空主题员工门户网站主页横幅的背景时,出现了这种情况。我想使用更少的星星来减少对主要内容的干扰,防止 CPU 过热,并且仍然使流星看起来是随机的。

不暂停

为了比较起见。

“原始”延迟方法

这是一个示例,说明我在我的流星动画分支中应用了 传统的关键帧延迟技术

这种方法包括确定我们希望迭代之间的延迟时间有多长,然后将关键帧压缩到 100% 的一部分。然后,我们将动画的最终状态保持到它达到 100% 以实现暂停。

@keyframes my-animation {
  /* Animation happens between 0% and 50% */
  0% {
    width: 0;
  }
  15% {
    width: 100px;
  }
  /* Animation is paused/delayed between 50% and 100% */
  50%, 100% {
    width: 0;
  }
}

我体验了这种方法的主要缺点:每个关键帧都必须手动调整,这有点痛苦,而且肯定容易出错。如果需要在心理上将所有关键帧重新转换回 100%,那么也更难理解动画在做什么。

新技术:在延迟期间隐藏

另一种技术是创建一个新的 @keyframes 集,它负责在延迟期间隐藏动画。然后,同时应用该动画和原始动画。

.target-of-animation {
  animation: my-awesome-beboop 1s, pause-between-iterations 4s;
}

@keyframes my-awesome-beboop {
  ...
}

@keyframes pause-between-iterations {
  /* Other animation is visible for 25% of the time */
  0% {
    opacity: 1;
  }
  25% {
    opacity: 1;
  }
  /* Other animation is hidden for 75% of the time */
  25.1% {
    opacity: 0;	
  }
  100% {
    opacity: 0;
  }
}

此技术的局限性在于,动画之间的暂停必须是“暂停”关键帧的整数倍。这是因为无限重复的关键帧将立即再次执行,即使有更长时间运行的关键帧应用于同一元素。

有趣的一点:当我开始撰写这篇文章时,我错误地认为缓动函数在 0% 时应用并在 100% 时结束。事实证明,缓动函数应用于每个 CSS 属性,从定义值的第一个关键帧开始,到定义值的下一个关键帧结束(例如,如果关键帧为 25% { left: 0 } 75% { left: 50px},则缓动曲线将从 25% 应用到 75%)。事后看来,这完全说得通,因为如果它是总缓动曲线的一个子集,则很难调整您的动画,但我的大脑有点被震撼了。

在上面的 my-awesome-beboop 关键帧示例中,my-awesome-beboop 将在 pause-between-animations 关键帧期间在后台运行三次,然后才会显示给用户,这看起来像是它的第二次循环(实际上是它第五次执行)。

这是一个使用此方法在流星之间添加延迟的示例

 

无法在延迟期间隐藏您的动画?

如果您需要在延迟期间将动画保持在屏幕上,除了隐藏之外还有另一个选项。您仍然可以使用第二组 @keyframes,但以抵消或抵消主要动画运动的方式为 CSS 属性设置动画。例如,如果您的主要动画使用 translateX,则可以在延迟 @keyframes 集中为 leftmargin-left 设置动画。

以下是一些示例

通过更改 transform-origin 暂停

通过抵消 transform: translateX 并为 left 属性设置动画来暂停

在暂停 translateX 动画的情况下,如果需要暂停动画超过一个迭代,则需要使用更复杂的 @keyframes

/* pausing the animation for three iterations */
@keyframes slide-left-pause {
  25%, 50%, 75% {
    left: 0;
  }
  37.5%, 62.5%, 87.5% {
    left: -100px;
  }
  100% {
    left: 0;
  }
}

在暂停期间,您可能会遇到一些轻微的抖动。在上面的 translateX 示例中,球在 slide-left-pause 期间存在一些轻微的振动,因为动画争夺主导地位。

总结

从性能方面来看,最佳选择是在延迟期间隐藏元素或为 transform 设置动画。为 leftmarginwidth 等属性设置动画比为 opacity 设置动画对处理器的占用要大得多(尽管 contain 属性似乎正在改变这一点)。

如果您对此有任何见解或意见,请告诉我!


感谢 Yusuke Nakaya 提供了 我在 CodePen 上分叉的原始流星 CSS 动画