停止无限 CSS3 动画并平滑恢复到初始状态
Stop infinite CSS3 animation and smoothly revert to initial state
使用关键帧动画构建 CSS3 加载程序时遇到一些问题。
加载器由 4 个动画上下移动的盒子组成。我遇到的问题是,当动画应该停止时,框会跳到初始位置。我正在寻找的行为是:加载程序无限动画直到加载完成,此时它应该动画到初始位置并停止,有点像 animation-iteration-count: infinite
并将其更改为 animation-iteration-count: 1
到停止动画。 (顺便说一句,这不起作用)。
看到这个 fiddle 明白我的意思:https://jsfiddle.net/cazacuvlad/qjmhm4ma/(当点击停止按钮时,盒子应该动画到初始位置,而不是跳跃)
基本设置是:
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
为了启动加载程序,我将包含动画的 loader-active
class 添加到 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-wrapper
class w/o loader-active
中的跨度并使用 animation-iteration-count
和 animation-play-state
当添加 loader-active
时没有任何运气。
找到了一个非常简单的解决方法。还是不纯CSS,有点JS,但是效果不错
已更新 fiddle:https://jsfiddle.net/cazacuvlad/qjmhm4ma/2/
我所做的是将 loader-active
class 移动到每个跨度(而不是包装器),在每个跨度上收听 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);
}
}
}
}
您还可以添加一个class,它指定迭代次数以停止无限循环。这种方法的优点是您可以更改 duration 和 timing-function 这对于缓和一些动画效果很好(比如旋转徽标例如)。
.animate-end {
animation-iteration-count: 3;
animation-duration: 1s;
animation-timing-function: ease-out;
}
我们可以用 js 添加这个 class,它现在会在计数 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>
使用关键帧动画构建 CSS3 加载程序时遇到一些问题。
加载器由 4 个动画上下移动的盒子组成。我遇到的问题是,当动画应该停止时,框会跳到初始位置。我正在寻找的行为是:加载程序无限动画直到加载完成,此时它应该动画到初始位置并停止,有点像 animation-iteration-count: infinite
并将其更改为 animation-iteration-count: 1
到停止动画。 (顺便说一句,这不起作用)。
看到这个 fiddle 明白我的意思:https://jsfiddle.net/cazacuvlad/qjmhm4ma/(当点击停止按钮时,盒子应该动画到初始位置,而不是跳跃)
基本设置是:
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
为了启动加载程序,我将包含动画的 loader-active
class 添加到 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-wrapper
class w/o loader-active
中的跨度并使用 animation-iteration-count
和 animation-play-state
当添加 loader-active
时没有任何运气。
找到了一个非常简单的解决方法。还是不纯CSS,有点JS,但是效果不错
已更新 fiddle:https://jsfiddle.net/cazacuvlad/qjmhm4ma/2/
我所做的是将 loader-active
class 移动到每个跨度(而不是包装器),在每个跨度上收听 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);
}
}
}
}
您还可以添加一个class,它指定迭代次数以停止无限循环。这种方法的优点是您可以更改 duration 和 timing-function 这对于缓和一些动画效果很好(比如旋转徽标例如)。
.animate-end {
animation-iteration-count: 3;
animation-duration: 1s;
animation-timing-function: ease-out;
}
我们可以用 js 添加这个 class,它现在会在计数 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>