破解 CSS 动画状态和播放时间 PlatoBlockchain 数据智能。 垂直搜索。 哎。

破解 CSS 动画状态和播放时间

纯 CSS 德军总部 是我几周前做的一个小项目。 这是一个使用 CSS 3D 转换和动画的实验。

设计灵感来自于 FPS 演示 而另一 德军总部密码笔,我决定建立自己的版本。 它大致基于原版 Wolfenstein 1D 游戏的第 9 集 - 3 楼。

编辑:这个游戏故意需要一些快速反应来避免游戏结束屏幕。

这是一个播放视频:

[嵌入的内容]

简而言之,我的项目只不过是一个精心编写的长 CSS 动画。 加上一些实例 复选框黑客.

:checked ~ div { animation-name: spin; }

环境由 3D 网格面组成,动画大多是普通的 3D 平移和旋转。 没什么特别的。

但是,有两个问题特别难以解决:

  • 每当玩家点击敌人时播放“武器开火”动画。
  • 当快速移动的老板得到最后一击时,进入一个戏剧性的慢动作。

在技​​术层面上,这意味着:

  • 选中下一个复选框时重播动画。
  • 选中复选框时减慢动画速度。

事实上,在我的项目中都没有得到妥善解决! 我要么最终使用了解决方法,要么就放弃了。

另一方面,经过一番挖掘,最终我找到了解决这两个问题的关键:改变运行 CSS 动画的属性。 在本文中,我们将进一步探讨这个主题:

  • 很多互动的例子。
  • 解剖:每个示例如何工作(或不工作)?
  • 幕后花絮:浏览器如何处理动画状态?

看着我 “扔我的砖头”.

问题 1:重放动画

第一个例子:“只是另一个复选框”

我的第一个直觉是“只需添加另一个复选框”,这不起作用:

每个复选框单独工作,但不能同时工作。 如果一个复选框已被选中,则另一个不再起作用。

以下是它的工作原理(或“不起作用”):

  1. animation-name of <div> is none 默认情况下。
  2. 用户点击一个复选框, animation-name 成为 spin, 动画从头开始。
  3. 过了一会儿,用户点击另一个复选框。 新的 CSS 规则生效,但 animation-name is 仍然 spin,这意味着没有添加或删除动画。 动画只是继续播放,就好像什么都没发生一样。

第二个例子:“克隆动画”

一种工作方法是克隆动画:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2; }

下面是它的工作原理:

  1. animation-name is none 原来。
  2. 用户点击“旋转!”, animation-name 成为 spin1. 动画 spin1 是从头开始的,因为它是刚刚添加的。
  3. 用户点击“再次旋转!”, animation-name 成为 spin2. 动画 spin2 是从头开始的,因为它是刚刚添加的。

请注意,在第 3 步中, spin1 由于 CSS 规则的顺序而被删除。 如果“再次旋转!”将不起作用首先检查。

第三个例子:“附加相同的动画”

另一种工作方法是“附加相同的动画”:

#spin1:checked ~ div { animation-name: spin; }
#spin2:checked ~ div { animation-name: spin, spin; }

这与前面的示例类似。 您实际上可以这样理解行为:

#spin1:checked ~ div { animation-name: spin1; }
#spin2:checked ~ div { animation-name: spin2, spin1; }

请注意,当“再次旋转!” 选中后,旧的运行动画将成为新列表中的第二个动画,这可能不直观。 一个直接的后果是:如果 animation-fill-mode is forwards. 这是一个演示:

如果你想知道为什么会这样,这里有一些线索:

  • animation-fill-mode is none 默认情况下,这意味着“如果不播放动画,则根本没有效果”。
  • animation-fill-mode: forwards; 意思是“动画播放完毕后,必须永远停留在最后一个关键帧”。
  • spin1的决定总是覆盖 spin2因为 spin1 稍后出现在列表中。
  • 假设用户点击“旋转!”,等待完全旋转,然后点击“再次旋转!”。 在这一刻。 spin1 已经完成,并且 spin2 刚刚开始。

讨论

经验法则:您不能“重新启动”现有的 CSS 动画。 相反,您想要添加和播放新动画。 这可以通过以下方式证实 W3C 规范:

一旦动画开始,它就会继续,直到它结束或动画名称被删除。

现在比较最后两个示例,我认为在实践中,“克隆动画”通常会更好,尤其是在 CSS 预处理器可用的情况下。

问题 2:慢动作

有人可能会认为减慢动画只是设置更长的时间 animation-duration:

div { animation-duration: 0.5s; }
#slowmo:checked ~ div { animation-duration: 1.5s; }

确实,这有效:

……或者是吗?

通过一些调整,应该更容易看到问题。

是的,动画变慢了。 不,它看起来不太好。 当您切换复选框时,狗(几乎)总是“跳跃”。 此外,这只狗似乎跳到了一个随机的位置,而不是最初的位置。 怎么来的?

如果我们引入两个“阴影元素”会更容易理解:

两个阴影元素都运行相同的动画但不同 animation-duration. 它们不受复选框的影响。

当您切换复选框时,元素会立即在两个阴影元素的状态之间切换。

引用 W3C 规范:

动画运行时对动画属性值的更改会应用,就好像动画从开始时就具有这些值一样。

这是继 无国籍 设计,它允许浏览器轻松确定动画值。 实际计算说明 此处此处.

另一种尝试

一个想法是暂停当前动画,然后添加一个较慢的动画从那里接管:

div {
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

所以它有效:

……或者是吗?

当您单击“Slowmo!”时,它确实会变慢。 但如果你等了一整圈,你会看到一个“跳跃”。 实际上,它总是跳到“Slowmo!”时的位置。 被点击。

原因是我们没有 from 定义了关键帧——我们不应该。 当用户点击“Slowmo!”时, spin1 在某个位置暂停,并且 spin2 从完全相同的位置开始。 我们根本无法事先预测那个位置……或者我们可以吗?

一个可行的解决方案

我们可以! 通过使用自定义属性,我们可以捕获第一个动画中的角度,然后将其传递给第二个动画:

div {
  transform: rotate(var(--angle1));
  animation-name: spin1;
  animation-duration: 2s;
}

#slowmo:checked ~ div {
  transform: rotate(var(--angle2));
  animation-name: spin1, spin2;
  animation-duration: 2s, 5s;
  animation-play-state: paused, running;
}

@keyframes spin1 {
  to {
    --angle1: 360deg;
  }
}

@keyframes spin2 {
  from {
    --angle2: var(--angle1);
  }
  to {
    --angle2: calc(var(--angle1) + 360deg);
  }
}

请注意: @property 本例中使用的是 并非所有浏览器都支持.

“完美”的解决方案

之前的解决方案有一个警告:“退出慢速模式”效果不佳。

这是一个更好的解决方案:

在这个版本中,可以无缝进入或退出慢动作。 也没有使用实验功能。 那么它是完美的解决方案吗? 是和不是。

这个解决方案就像“换档”“齿轮”一样工作:

  • 齿轮:有两个 <div>s。 一个是另一个的父母。 两者都有 spin 动画但有不同 animation-duration. 元素的最终状态是两个动画的累加。
  • 换档:一开始只有一个 <div> 它的动画正在运行。 另一个暂停。 当复选框被切换时,两个动画交换它们的状态。

虽然我真的很喜欢这个结果,但有一个问题:这是一个很好的利用 spin 动画,通常不适用于其他类型的动画。

一个实用的解决方案(带 JS)

对于一般的动画,可以用一点 JavaScript 来实现慢动作功能:

快速说明:

  • 自定义属性用于跟踪动画进度。
  • 当复选框被切换时,动画会“重新启动”。
  • JS代码计算正确 animation-delay 以确保无缝过渡。 我建议 本文 如果你不熟悉负值 animation-delay.

您可以将此解决方案视为“重新启动动画”和“换档”方法的混合体。

在这里正确跟踪动画进度很重要。 解决方法是可能的,如果 @property 不可用。 例如,这个版本使用 z-index 跟踪进度:

旁注:最初,我也尝试创建纯 CSS 版本,但没有成功。 虽然不是 100% 肯定,但我认为这是因为 animation-delay is 不可动画.

这是一个带有最少 JavaScript 的版本。 只有“进入慢动作”有效。

如果您设法创建一个可用的纯 CSS 版本,请告诉我!

慢动作任何动画(使用 JS)

最后,我想分享一个适用于(几乎)任何动画的解决方案,即使有多个复杂的 @keyframes:

基本上,你需要添加一个动画进度跟踪器,然后仔细计算 animation-delay 对于新动画。 但是,有时获取正确的值可能很棘手(但可能)。

例如:

  • animation-timing-function 是不是 linear.
  • animation-direction 是不是 normal.
  • 中的多个值 animation-name 具有不同 animation-duration的和 animation-delayS.

也描述了这种方法 此处 等加工。为 网络动画 API.

致谢

在遇到纯 CSS 项目后,我开始走这条路。 有些是 精致的艺术品,有些是 复杂的装置. 我最喜欢的是那些涉及 3D 对象的,例如,这个 弹跳球包装立方体.

一开始,我不知道这些是如何制作的。 后来我阅读并从中学到了很多 Ana Tudor 的这个不错的教程.

事实证明,使用 CSS 构建和动画 3D 对象与使用 CSS 没有太大区别 混合器,只是有点不同的味道。

结论

在本文中,我们检查了 CSS 动画在 animate-* 属性被改变。 特别是我们制定了“重播动画”和“动画慢动作”的解决方案。

我希望你觉得这篇文章很有趣。 请让我知道你的想法!

时间戳记:

更多来自 CSS技巧