css 个动画即使在不同时间开始也一起结束

css animations end together even though they are started at different times

我有几个相同类型的元素,我希望它们共享相同的 css 动画,但我希望它们在不同时间 start/end 动画。

Codepen for the following code

html:

<div class="container">
    <div class="box hidden"></div>
</div>
<div class="container">
    <div class="box hidden"></div>
</div>
<div class="container">
    <div class="box hidden"></div>
</div>

css:

.container {
    width: 100px;
    height: 100px;
    margin-bottom: 20px;
}

.box {
    width: 100%;
    height: 100%;
}

.box.hidden {
    visibility: hidden;
}

.box {
    animation: growIn 1s;
    animation-timing-function: cubic-bezier(.46,.13,.99,.83);
    transition: all .2s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.container:first-child .box {
    background-color: green;
}

.container:nth-child(2) .box {
    background-color: orange;
}

.container:nth-child(3) .box {
    background-color: red;
}

@keyframes growIn {
    from {
        transform: scale(0);
    }
    to {
        transform: scale(1);
    }
}

box 元素开始时是隐藏的,然后使用 javascript 我从不同的框中但在不同的时间删除了这个类名:

const boxes = document.querySelectorAll(".box");
boxes.forEach(box => {
    setTimeout(() => box.classList.remove("hidden"), Math.random() * 1000);
});

发生的情况是所有 3 个盒子同时结束它们的动画。动画确实在不同的时间开始,但都一起结束。

这是为什么?
如果我这样做但添加一个类名而不是删除它(为了使动画开始)那么它的行为就像我想要的那样。
有任何想法吗?谢谢。

问题是您的盒子元素以 .box class 开头,这是动画 class。这意味着动画从元素加载的那一刻开始,无论它们是否隐藏。这意味着当您删除 "hidden" class 时,它们只会在动画期间的某个时刻显示自己。

您要做的是重命名动画 class,例如 "grower"

.grower {
    animation: growIn 1s;
    animation-timing-function: cubic-bezier(.46,.13,.99,.83);
    transition: all .2s cubic-bezier(0.215, 0.61, 0.355, 1);
}

然后在 javascript 循环中加入:

const boxes = document.querySelectorAll(".box");
boxes.forEach(box => {
  setTimeout(() => {
    box.classList.remove("hidden");
    box.classList.add("grower"); }, Math.random() * 1000);
});

这里有一个片段来展示它的实际效果:

const boxes = document.querySelectorAll(".box");
boxes.forEach(box => {
  setTimeout(() => {
    box.classList.remove("hidden");
    box.classList.add("grower"); }, Math.random() * 1000);
});
.container {
  width: 100px;
  height: 100px;
  margin-bottom: 20px;
}

.box {
  width: 100%;
  height: 100%;
}

.box.hidden {
  visibility: hidden;
}

.grower {
 animation: growIn 1s;
 animation-timing-function: cubic-bezier(.46,.13,.99,.83);
 transition: all .2s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.container:first-child .box {
  background-color: green;
}

.container:nth-child(2) .box {
  background-color: orange;
}

.container:nth-child(3) .box {
  background-color: red;
}

@keyframes growIn {
  from {
  transform: scale(0);
  }
  to {
  transform: scale(1);
  }
}
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>

只是因为所有的动画已经同时开始了。使用 visibility:hidden 不会阻止动画开始并使其在元素可见时稍后开始。例如,不透明度也会发生同样的事情:

const boxes = document.querySelectorAll(".box");
boxes.forEach(box => {
  setTimeout(() => box.classList.remove("hidden"), Math.random() * 5000);
});
.container {
  width: 100px;
  height: 100px;
  margin-bottom: 20px;
}

.box {
  width: 100%;
  height: 100%;
}

.box.hidden {
  opacity: 0.1;
}

.box {
  animation: growIn 5s;
  animation-timing-function: cubic-bezier(.46, .13, .99, .83);
  transition: all .2s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.container:first-child .box {
  background-color: green;
}

.container:nth-child(2) .box {
  background-color: orange;
}

.container:nth-child(3) .box {
  background-color: red;
}

@keyframes growIn {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>

如果您改用 display 属性,您可以看到您正在寻找的行为:

const boxes = document.querySelectorAll(".box");
boxes.forEach(box => {
  setTimeout(() => box.classList.remove("hidden"), Math.random() * 3000);
});
.container {
  width: 100px;
  height: 100px;
  margin-bottom: 20px;
}

.box {
  width: 100%;
  height: 100%;
}

.box.hidden {
  display:none;
}

.box {
  animation: growIn 1s;
  animation-timing-function: cubic-bezier(.46, .13, .99, .83);
  transition: all .2s cubic-bezier(0.215, 0.61, 0.355, 1);
}

.container:first-child .box {
  background-color: green;
}

.container:nth-child(2) .box {
  background-color: orange;
}

.container:nth-child(3) .box {
  background-color: red;
}

@keyframes growIn {
  from {
    transform: scale(0);
  }
  to {
    transform: scale(1);
  }
}
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>
<div class="container">
  <div class="box hidden"></div>
</div>


来自specification:

The 'visibility' property specifies whether the boxes generated by an element are rendered.

Invisible boxes still affect layout (set the 'display' property to 'none' to suppress box generation altogether).

因此,与使用 display.

时不同,使用 visibility 总是 生成框

如果我们检查与动画相关的 specification,我们会发现:

Setting the display property to none will terminate any running animation applied to the element and its descendants. If an element has a display of none, updating display to a value other than none will start all animations applied to the element by the animation-name property, as well as all animations applied to descendants with display other than none.