The CSS animations and transitions are potent ways of animating properties in our stylesheet with the assist of the browser. With the two related JavaScript events, called animationend and transitionend, we can do even more.
Using transition and animation, we can make complex animations with just CSS, and the browser will do the hard work. In this way, we can achieve smooth 60 FPS animations with only a few lines.
Alone the stylesheet animation is often enough, but there are scenarios when we need more. For example, when we want to detect the end of the animation; which if not so frequent but happens in complicated stuff. If we’re going to catch the completion of animation we need an event base callback where we can run our related code.
About Transition and Animation End
The two events are like any other type of event, but these are triggered when a CSS animation or transition arrived at the end of the actual cycle.
You set your movement like you always do, and also configure the JavaScript part (add, remove classes on different interactions in case of a transition) if needed. You add a new event listener to the element to catch the completion of the animation.
Depending on what type of animation method you use, you have to set the correct event: transitionend or animationend.
To detect the events you can also use the ontransitionend and onanimationend properties.
Catch the Transitionend Event
Let’s see a basic example of a transition. We will toggle a class named animate on the circle element. The catch is that when the movement stops, we will remove the previously appended selector to create a bounce effect (the item returns to the start position).
Using the transitionend, we can correctly catch the right moment for the class to remove. Note that we removed the transitionend event listener after the event triggered so the next time it doesn’t duplicate (for this you need a unique callback function) itself. Always a good practice to destroy the unnecessary event listeners!
let item = document.querySelector('.circle'); item.addEventListener('click', (e) => { item.classList.toggle('animate'); item.addEventListener(transitionEvent, transitionEndCallback); }); transitionEndCallback = (e) => { item.removeEventListener(transitionEvent, transitionEndCallback); item.classList.remove('animate'); }
See the Pen
Catch Transition End with JavaScript by Adam Laki (@adamlaki)
on CodePen.
Catch Only the Needed Property Name
As you see in this example, we used transition: transform 1s; line to move our element. The catched transitioned property is the transform. But what if we have multiple changes/transitions (which needed to a sophisticated result)? Well, we can identify them with the event object’s propertyName property, which gives back the current name of the transitioned property.
if (!event.propertyName === 'height') return;
Note that you can also have access to this property catching animationend.
Catch the Animationend Event
We made the same effect in case of the animation example. Although in the CSS logic it looks different, the JavaScript part do the same. We declared a single keyframe which transforms the object by the Y-axis back and forth.
var item = document.querySelector('.circle'); item.addEventListener('click', (e) => { item.classList.toggle('animate'); item.addEventListener('animationend', animationEndCallback); }); animationEndCallback = (e) => { item.removeEventListener('animationend', animationEndCallback); item.classList.remove('animate'); }
See the Pen
animationend Vanilla JavaScript by Adam Laki (@adamlaki)
on CodePen.
Use the Correct Event name
There is a catch with the event names: you need prefixes if you want to support legacy browsers. There exist two simple helpers (from David Walsh) which help you identify the correct event name.
whichTransitionEvent = () => { let t, el = document.createElement("fakeelement"); let transitions = { "transition" : "transitionend", "OTransition" : "oTransitionEnd", "MozTransition" : "transitionend", "WebkitTransition": "webkitTransitionEnd" } for (t in transitions){ if (el.style[t] !== undefined){ return transitions[t]; } } }
The Old Way of Detecting the End of an Animation
Nice to know that the old way to make some callback like behavior is to use a timeout (using setTimeout function) with the transition or animation interval when switching the state. It is not the best solution because of the browser’s optimized working processes.
Although in the good old days we didn’t have any correct solution now with the events we can catch just the end.
Closing remarks
You won’t use this technique in your normal development, but it can be handy. We developed an off-canvas navigation lately, and to display a background overlay when the menu is open, we had to catch the end of the opening animation.
If you want to animate with class switching, you can do it easily through the classList API.