How to Detect When CSS Animations Start and End with JavaScript

Detect the end of specific CSS animation of an element

You could look for a specific animationName property of the animationend event, e.g.

let d = document.querySelector('div')

d.addEventListener('animationend', function(ev) {

if (ev.animationName === 'fade') {

alert('end')

}

})
div {

margin: 100px;

width: 100px;

height: 100px;

background: yellowgreen;

animation: fade 5s linear 0s 1,

resize 2s linear 0s forwards;



}

@keyframes fade {

from { opacity: 1 }

to { opacity: 0 }

}

@keyframes resize {

from { transform: scaleX(1) }

to { transform: scaleX(2) }

}
<div></div>

Detect which CSS animation just ended in JavaScript?

From jQuery you can access the originalEvent object, and, from there, the animationName property:

$('body').on('webkitAnimationEnd', function(e){
var animName = e.originalEvent.animationName;
console.log(animName);
});​

(Webkit-only) JS Fiddle demo.

From there, simply use an if to check what the animation name is/was (past-tense, I suppose, given that it ended).

The above updated, to give possibly a better illustration:

$('div').on('webkitAnimationEnd', function(e){
var animName = e.originalEvent.animationName;
if (animName == 'bgAnim') {
alert('the ' + animName + ' animation has finished');
}
});​

(Webkit-only) JS Fiddle demo.

This demo uses the following HTML:

<div><span>text</span></div>​

And CSS:

@-webkit-keyframes bgAnim {
0%, 100% {
color: #000;
background-color: #f00;
}
50% {
color: #fff;
background-color: #0f0;
}
}

@-webkit-keyframes fontSize {
0%, 100% {
font-size: 100%;
}
50% {
font-size: 300%;
}
}

div {
font-weight: bold;
-webkit-animation: bgAnim;
-webkit-animation-duration: 2s;
-webkit-animation-iteration-count: 2;
}

span {
font-size: 100%;
font-weight: bold;
-webkit-animation: fontSize;
-webkit-animation-duration: 4s;
-webkit-animation-iteration-count: 1;
}

Check if an CSS animation is completed with JQuery or JS?

You need to listen to for the animationend and webkitAnimationEnd events in javascript.

Like this:

$('div').on('animationend webkitAnimationEnd', function() { 
alert('end');
});

$('div').on('animationend webkitAnimationEnd', function() { 

alert('end');

});
div {

width: 100px;

height: 100px;

animation-name: test;

animation-duration: 5s

}

@keyframes test {

from {background-color: red;}

to {background-color: blue;}

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div></div>

How to detect state of CSS transition via JS and skip it

You can listen to transition event and remove it on demand:

const el = document.getElementById('transition');
let isAnimating = false;

el.addEventListener('transitionstart', function() {
isAnimating = true;
});

el.addEventListener('transitionend', () => {
isAnimating = false;
});

el.addEventListener('transitioncancel', () => {
isAnimating = false;
});

function removeTransition(checkIfRunning) {
if (checkIfRunning && !isAnimating) {
return;
}

el.style.transition = "none";
}
#transition {
width: 100px;
height: 100px;
background: rgba(255, 0, 0, 1);
transition-property: transform background;
transition-duration: 2s;
transition-delay: 1s;
}

#transition:hover {
transform: rotate(90deg);
background: rgba(255, 0, 0, 0);
}
<div id="transition">Hello World</div>
<br />
<button onclick="removeTransition(false)">Remove Transition</button>
<br />
<br />
<button onclick="removeTransition(true)">Remove Transition on if running</button>

Is there a reliable way to detect when all animations for a given element and its children are completed?

There is no ready cake I know that tells you this. But developing classified JavaScript and CSS code you can do this. I don't know your code. So you are at your own from this point but I will leave you with few points:

  • Separate logic from effect by using JavaScript/jQuery to trigger events while reserving CSS3 for the effects they trigger.
  • Use transitionend to detect when transitions have ended, allowing for callback-like behaviour on jQuery methods that don’t allow callbacks.
  • If animation is manipulated by JavaScript, trigger actions at end of script functions or loops depending on your code.
  • Use animationend in the same way in relation to CSS3 keyframe animations.

But in short you have to do this on your own writing animations.

References

transitionend on MDN

animationend on MDN

Check in javascript if a CSS3 animation is currently running on a DOM element

As you seem to use animation CSS for your animations (given that you use the animationend event), you could use getComputedStyle to verify the content of the animation-name CSS property.

Here is a demo with two buttons: one triggers an animation on click, while the other doesn't:

$("button").click(function () {

buttonClick($(this));

});

function hasAnimation($button) {

return getComputedStyle($button[0], null)["animation-name"] != "none";

}

function onEndAnimation($button) {

$button.removeClass('activated');

console.log("animation complete on button " + $button.text());

}

function buttonClick($button) {

$button.addClass('activated');

$button.one('animationend', () => onEndAnimation($button));

if (!hasAnimation($button)) onEndAnimation($button);

}
#yes.activated {

animation-duration: 1s;

animation-name: grow;

}

@keyframes grow {

from { width: 50px; }

50% { width: 100px; }

to { width: 50px; }

}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<button id="yes" style="width: 50px">Yes</button><br>

<button id = "no" style="width: 50px">No</button>

Detect element CSS animation end, child items firing the event

animationend bubbles, so animations on descendant elements bubble up to the parent.

If you only want to handle the event when it relates specifically to elm (this.$refs.container), compare event.target to elm (or event.currentTarget) and ignore the event if they don't match:

elm.addEventListener('transitionend', event => {
if (event.target !== event.currentTarget) {
return; // Ignore it
}
console.log(event.target);
});

Updated Example (I've added a border to the container so you can see the animation occur and see that the console.log happens when it ends):

Vue.component('test', {
data: function () {
return {
count: 0
}
},
methods: {
expand() {
const elm = this.$refs.container;

elm.addEventListener('transitionend', event => {
if (event.target !== event.currentTarget) {
return; // Ignore it
}
console.log(event.target);
});

elm.style.height = '100px';
}
},
template: `
<div>
<p @click="expand()">Expand</p>
<div class="container"
ref="container">
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<li>Item 4</li>
</ul>
</div>
</div>
`
})

new Vue().$mount('#app');
.container {
transition: height .3s ease;
height: 0;
border: 1px solid grey;
}
.container ul li:hover {
background: red;
}
.container ul li {
transition: background .2s ease-in-out;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<test></test>
</div>


Related Topics



Leave a reply



Submit