停止无限CSS3动画并平滑恢复到初始状态

Stop infinite CSS3 animation and smoothly revert to initial state

本文关键字:平滑 恢复 初始状态 动画 无限 CSS3      更新时间:2023-09-26

使用关键帧动画构建 CSS3 加载器时遇到一些问题。

加载器由 4 个框组成,这些框可以动画上下移动。我遇到的问题是,当动画应该停止时,框会跳到初始位置。我正在寻找的行为是:加载器无限动画,直到加载完成,此时它应该动画到初始位置并停止,有点像animation-iteration-count: infinite并将其更改为animation-iteration-count: 1以停止动画。(顺便说一句,这不起作用)。

看看这个小提琴,明白我的意思:https://jsfiddle.net/cazacuvlad/qjmhm4ma/(单击停止按钮时,框应该动画到初始位置,而不是跳跃)

基本设置是:

<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>

为了启动加载器,我将一个包含动画的loader-active类添加到loader-wrapper

少:

.loader-wrapper {
  &.loader-active {
    span {
      .animation-name(loader);
      .animation-duration(1200ms);
      .animation-timing-function(ease-in-out);
      .animation-play-state(running);
      .animation-iteration-count(infinite);
      &:nth-child(1) {
      }
      &:nth-child(2) {
        .animation-delay(300ms);
      }
      &:nth-child(3) {
        .animation-delay(600ms);
      }
      &:nth-child(4) {
        .animation-delay(900ms);
      }
    }
  }
}

我尝试将动画添加到没有loader-activeloader-wrapper类中的跨度中,并在添加loader-active时玩弄animation-iteration-countanimation-play-state没有任何运气。

找到了一个非常简单的解决方法。仍然不是纯粹的CSS,它涉及一些JS,但它运行良好。

更新的小提琴:https://jsfiddle.net/cazacuvlad/qjmhm4ma/2/

我所做的是将loader-active类移动到每个跨度(而不是包装器),侦听每个跨度上的animationiteration事件,然后停止动画。

$('.loader-wrapper span').on('animationiteration webkitAnimationIteration', function () {
  var $this = $(this);
  $this.removeClass('loader-active');
  $this.off();
});

这基本上在迭代周期结束时停止动画。

更新的 收起

.loader-wrapper {
  span {
    &.loader-active {
      .animation-name(loader);
      .animation-duration(1200ms);
      .animation-timing-function(ease-in-out);
      .animation-play-state(running);
      .animation-iteration-count(infinite);
      &:nth-child(1) {
      }
      &:nth-child(2) {
        .animation-delay(300ms);
      }
      &:nth-child(3) {
        .animation-delay(600ms);
      }
      &:nth-child(4) {
        .animation-delay(900ms);
      }
    }
  }
}

您还可以添加一个类,该类指定迭代计数以停止无限循环。这种方法的优点是您可以更改持续时间计时功能,这对于缓和一些动画(例如旋转徽标)非常有用。

.animate-end {
  animation-iteration-count: 3;
  animation-duration: 1s;
  animation-timing-function: ease-out;
}

我们可以用 js 添加这个类,它现在将在计数 3 时停止动画。

document.querySelector(".loader-wrapper").classList.add("animate-end");

但你也可以通过计数来结束当前的迭代,并使用 Js 动态地更改元素的样式。

let iterationCount = 0;
document.querySelector(".loader-wrapper span").addEventListener('animationiteration', () => {
//count iterations
  iterationCount++;
});    
yourElement.style.animationIterationCount = iterationCount + 1;

下面是一个包含您的代码的演示:

document.querySelector("#start_loader").addEventListener("click", function(){
  document.querySelector(".loader-wrapper").classList.add("loader-active");  
})

let iterationCount = 0;
document.querySelector(".loader-wrapper span").addEventListener('animationiteration', () => {
//count iterations
  iterationCount++;
  console.log(`Animation iteration count: ${iterationCount}`);
});
document.querySelector("#stop_loader").addEventListener("click", function(){
    
    //For some animation it can be nice to change the duration or timing animation
    document.querySelector(".loader-wrapper").classList.add("animate-end");
    
    //End current iteration
     document.querySelectorAll(".loader-wrapper span").forEach(element => {
        element.style.animationIterationCount = iterationCount + 1;
    });

    //Remove Classes with a timeout or animationiteration event
    setTimeout(() => {
        document.querySelector(".loader-wrapper").classList.remove("loader-active");
         document.querySelector(".loader-wrapper").classList.remove("animate-end");
     }, 1200);
    
})
@-moz-keyframes 'loader' {
  0% {
    -moz-transform: translate3d(0, 0, 0);
  }
  50% {
    -moz-transform: translate3d(0, -10px, 0);
  }
  100% {
    -moz-transform: translate3d(0, 0, 0);
  }
}
@-webkit-keyframes 'loader' {
  0% {
    -webkit-transform: translate3d(0, 0, 0);
  }
  50% {
    -webkit-transform: translate3d(0, -10px, 0);
  }
  100% {
    -webkit-transform: translate3d(0, 0, 0);
  }
}
@-o-keyframes 'loader' {
  0% {
    -o-transform: translate3d(0, 0, 0);
  }
  50% {
    -o-transform: translate3d(0, -10px, 0);
  }
  100% {
    -o-transform: translate3d(0, 0, 0);
  }
}
@keyframes 'loader' {
  0% {
    transform: translate3d(0, 0, 0)
  }
  50% {
    transform: translate3d(0, -10px, 0)
  }
  100% {
    transform: translate3d(0, 0, 0)
  }
}
.loader-wrapper {
  margin-bottom: 30px;
}

.loader-wrapper.loader-active span {
  -webkit-animation-name: loader;
  -moz-animation-name: loader;
  -ms-animation-name: loader;
  -o-animation-name: loader;
  animation-name: loader;
  -webkit-animation-duration: 1200ms;
  -moz-animation-duration: 1200ms;
  -ms-animation-duration: 1200ms;
  -o-animation-duration: 1200ms;
  -webkit-animation-timing-function: ease-in-out;
  -moz-animation-timing-function: ease-in-out;
  -ms-animation-timing-function: ease-in-out;
  -o-animation-timing-function: ease-in-out;
  animation-timing-function: ease-in-out;
  -webkit-animation-play-state: running;
  -moz-animation-play-state: running;
  -ms-animation-play-state: running;
  -o-animation-play-state: running;
  animation-play-state: running;
  -webkit-animation-iteration-count: infinite;
  -moz-animation-iteration-count: infinite;
  -ms-animation-iteration-count: infinite;
  -o-animation-iteration-count: infinite;
  animation-iteration-count: infinite;
}

.loader-wrapper.animate-end span {
    /* Works great for some animations */
    /*animation-iteration-count: 1;*/
    /*animation-duration: 1s;*/
}
.loader-wrapper.loader-active span:nth-child(1) {}
.loader-wrapper.loader-active span:nth-child(2) {
  animation-delay: 300ms;
}
.loader-wrapper.loader-active span:nth-child(3) {
  animation-delay: 600ms;
}
.loader-wrapper.loader-active span:nth-child(4) {
  animation-delay: 900ms;
}
.loader-wrapper span {
  margin-right: 5px;
  display: inline-block;
  vertical-align: middle;
  background: black;
  width: 10px;
  height: 10px;
}
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
<button id="start_loader">Start</button>
<button id="stop_loader">Stop</button>