移除 CSS class 后过渡到默认值 class 并带有动画

Transition to default class upon removal of CSS class with animation

我正在为按钮制作动画。 class 根据我的应用程序状态分配。这在 Svelte 中实际上是这样实现的:

<div class="default"
     class:run-animation="{$animate === true}">
但是在没有 Svelte 的情况下 javascript 中的等价物是:

let element = document... (find element)
element.classList.add("run-animation")
... later ...
element.classList.remove("run-animation)
为了最小的可重现示例,我尝试 animate/transition 之间的 classes 看起来像这样:

.default {
    top: 20px;
    color: white;
}

@keyframes button-animation {
  from {
    top: 20px;
    color: white;
  }
  20% {
    top: 23px;
    color: white;
  }
  25% {
    color: red;
  }
  100% {
    top: 23px;
    color: red;
  }
}

.run-animation {
  animation-name: button-animation;
  animation-duration: 2s;
  /* Preserve the effect of the animation at ending */
  animation-fill-mode: forwards;
}

我将 class 添加到元素中,按钮就会按照我想要的方式进行动画处理。当我删除 class 时,我的问题出现了。我希望按钮平滑地过渡回默认值 CSS。我尝试将动画添加到 运行-animate class:

.run-animation {
  animation-name: ... ;
  
  top: 23px;
  color: red;
}

我遇到很多人说,如果我将转换 属性 添加到默认值 class,则移除 class 后的转换将适用。我试过如下:

.default {
  ...
  transition: all 3s linear;
}
但它不起作用。添加时动画 运行 很流畅,但删除 class 后样式会立即恢复为默认样式(无平滑过渡)。

我的目标:当动画 class 被移除时,我想从动画的结束状态平滑过渡到默认的 class。这可能吗?

理想情况下,我在顶部添加带有 Svelte 逻辑的 class,因此动画不应在 javascript 中触发,而是由于 class 而自然发生作业。

(我的实际代码比显示的要复杂一些,按钮有另一个 class 样式根本没有动画,动画包含更多样式,例如框阴影和文本阴影。不过,我不明白为什么这比上面包含的颜色和顶部更成问题)

// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
  document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {position: absolute; left: 120px}
div.default {
  position: absolute;
  width: 100px;
  height: 100px;
  background: darkgreen;
}
/* Above code to make a visible working example */

div.default {
  top: 20px;
  color: white;
  transition: top 0.4s, color 0.1s 0.4s;
}

@keyframes define-animation {
  from {
    top: 20px;
    color: white;
  }
}

div.default.animation {
  animation-name: define-animation;
  animation-duration: 2s;
  
  top: 24px;
  color: red;
}
<div class="default">I'm colourful</div>
<button>Toggle ".animation"-class</button>

以上是一个工作片段,其中包含 运行 添加 class 时的动画,class 删除时没有反向转换。我尝试在 .default 和 .animation 中将动画方向设置为相反的值。我尝试在属性的关键帧中的 class and/or 中定义 .animate 结束状态属性。

编辑:现在可以使用了!如何? 您不能申请: 动画填充模式:转发; 结束属性需要在动画中定义 class 而不是在关键帧中。

添加 class 时播放动画。移除 class 时使用过渡时间(如果动画已完成)。

要获得过渡效果,可以使用transition-属性。
transition-属性 可以在这里使用,因为每个要设置动画的 属性 都只有一个开始值和结束值。

将动画百分比转换为秒
要将 CSS Animation button-animation 的百分比转换为秒,您只需计算 'percentage' * 'animation-duration'.
这适用于 transition-duration-属性 以及 transition-delay-属性.

示例:
color 正在从 20% 到 25% 进行动画处理,持续时间为 5%,延迟为 20%。
总之,动画应该需要 2 秒。 所以我们计算:

  • transition-duration: 5% * 2s = 0.1s
  • transition-delay: 20% * 2s = 0.4s

这样,我们可以将 transition: color 0.1s 0.4s 添加到 .default-class。

为什么要添加到 .default,而不是 .animation
如果我们将 transition-属性 添加到 .animation,则会发生以下情况:

  • 添加 .animation 时会有过渡效果,因为元素现在定义了 transition-属性。
  • 但是当删除 .animation 时,元素将 不再 定义 transition-属性,这意味着不会有过渡.

现在,我们希望在添加和删除 .animation 时进行转换,这意味着我们希望在存在 .animation 和存在时定义 transition-属性当它不是。这意味着,transition 不应定义在 .animation.

// JS only toggles '.animation'
document.querySelector("button").addEventListener("click", () => {
  document.querySelector("div.default").classList.toggle("animation");
});
body {display: flex}
button {align-self: center}
div.default {
  position: relative;
  border: 2px solid black;
  width: 100px;
  height: 100px;
  background: darkgreen;
}
/* Above code to make a visible working example */

div.default {
  top: 20px;
  color: white;
  transition: top 0.4s, color 0.1s 0.4s;
}
div.default.animation {
  top: 23px;
  color: red;
}
<div class="default">Some text to see the "color"-property</div>
<button>Toggle ".animation"-class</button>

为什么它的行为不同...
...当将属性放在动画的 to 部分时,而不是将它们放在 .animation 本身?

也就是说,因为属性没有直接应用到元素本身,而是元素停止在它的动画中(就在最后),只给出 外观 实际应用的属性。
移除 animation-fill-mode: forwards 会显示在 动画播放后 实际应用的属性。那些实际应用的属性将是删除 .animationtransition 的起始值。

.animation 中定义这些属性时,它们将固有地成为动画的 to 值(如果未在动画本身中另外定义), 是元素的应用属性。
这意味着,当删除 .animation 时,转换将从那里开始。