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
Event.Preventdefault() Function Not Working in Ie
How to Handle Newlines in Json
Padding or Margin Value in Pixels as Integer Using Jquery
Change CSS of Class in JavaScript
How to Crop an Image at Client Side Using Jcrop and Upload It
Dynamically Expand Height of Input Type "Text" Based on Number of Characters Typed into Field
How to Run Background Tasks in React Native
What Is the Standard Solution in JavaScript for Handling Big Numbers (Bignum)
Check If Element Is Visible in Dom
How to Add Hours to a Date Object
Convert Xml to Json (And Back) Using JavaScript
How to Show Live Preview in a Small Popup of Linked Page on Mouse Over on Link
Setting Minimum Size Limit for a Window Minimization of Browser
How to Get Border Width in Jquery/Javascript
Event Listener on a CSS Pseudo-Element, Such as ::After and ::Before
How to Have a Host and Container Read/Write the Same Files with Docker
Why Can't I Access a Property of an Integer with a Single Dot