admin管理员组文章数量:1289517
Having some trouble building a CSS3 loader using keyframe animations.
The loader consists of 4 boxes that animate going up and down. The issue I'm having is that when the animation is supposed to stop, the boxes jump to the initial position. The behaviour I'm looking for is: loader is animating infinitely until loading is done, at which point it should animate to the initial position and stop, sort of like having animation-iteration-count: infinite
and changing it to animation-iteration-count: 1
to stop the animation. (which doesn't work btw).
See this fiddle to see what I mean: / (when clicking the stop button, the boxes should animate to the initial position, instead of jumping)
The basic setup is:
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
To start the loader, I'm adding a loader-active
class that contains the animation to the loader-wrapper
.
LESS:
.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);
}
}
}
}
I've tried adding the animation to the spans in the loader-wrapper
class w/o loader-active
and playing around with animation-iteration-count
and animation-play-state
when loader-active
is added without any luck.
Having some trouble building a CSS3 loader using keyframe animations.
The loader consists of 4 boxes that animate going up and down. The issue I'm having is that when the animation is supposed to stop, the boxes jump to the initial position. The behaviour I'm looking for is: loader is animating infinitely until loading is done, at which point it should animate to the initial position and stop, sort of like having animation-iteration-count: infinite
and changing it to animation-iteration-count: 1
to stop the animation. (which doesn't work btw).
See this fiddle to see what I mean: https://jsfiddle/cazacuvlad/qjmhm4ma/ (when clicking the stop button, the boxes should animate to the initial position, instead of jumping)
The basic setup is:
<div class="loader-wrapper"><span></span><span></span><span></span><span></span></div>
To start the loader, I'm adding a loader-active
class that contains the animation to the loader-wrapper
.
LESS:
.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);
}
}
}
}
I've tried adding the animation to the spans in the loader-wrapper
class w/o loader-active
and playing around with animation-iteration-count
and animation-play-state
when loader-active
is added without any luck.
- You can't do that with CSS. You'd need what I suspect would be quick plex Javascript. – Paulie_D Commented Feb 19, 2016 at 14:20
- Doing it in JS is the backup solution. I think this is valid use case for animations, there should be a pure CSS way of doing this. – Vlad Cazacu Commented Feb 19, 2016 at 14:26
- The animations are fine but CSS can't detect where an animation is in it's (mid)cycle and then run down based on a condition. I'm not even sure if JS can do that but if it can, that would be the way. – Paulie_D Commented Feb 19, 2016 at 14:28
- 1 It might not be impossible but it would not be straight-forward. You can refer to this thread. Within that answer I have linked to another answer by vals which shows a method to achieve something like this. (Note: I linked to my answer instead of directly linking to vals' because there is some explanation in my answer which might also be helpful for you.) – Harry Commented Feb 19, 2016 at 14:55
- 1 I found a pretty simple workaround, not entirely happy with it since it still involves JS, but it works well. Posting it as an answer in case someone else stumbles on this. – Vlad Cazacu Commented Feb 19, 2016 at 15:04
2 Answers
Reset to default 8Found a pretty simple workaround. Still not pure CSS, it involves a bit of JS, but it works well.
Updated fiddle: https://jsfiddle/cazacuvlad/qjmhm4ma/2/
What I did was to move the loader-active
class to each span (instead of the wrapper), listen to the animationiteration
event on each span and stop the animation then.
$('.loader-wrapper span').on('animationiteration webkitAnimationIteration', function () {
var $this = $(this);
$this.removeClass('loader-active');
$this.off();
});
This basically stops the animation at the very end of an iteration cycle.
Updated LESS
.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);
}
}
}
}
You can also add a class which specifies the iteration count to stop the infinite loop. The advantage of this approach is that you can change the duration and timing-function which can be nice for easing out some animation (Like a rotating logo for example).
.animate-end {
animation-iteration-count: 3;
animation-duration: 1s;
animation-timing-function: ease-out;
}
We can add this class with js and it will now stop the animation at count 3.
document.querySelector(".loader-wrapper").classList.add("animate-end");
But you can also end the current itertion by counting it and change the style of the element dynamcly with Js.
let iterationCount = 0;
document.querySelector(".loader-wrapper span").addEventListener('animationiteration', () => {
//count iterations
iterationCount++;
});
yourElement.style.animationIterationCount = iterationCount + 1;
Here is a demo with your code:
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>
本文标签: javascriptStop infinite CSS3 animation and smoothly revert to initial stateStack Overflow
版权声明:本文标题:javascript - Stop infinite CSS3 animation and smoothly revert to initial state - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741397202a2376450.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论