CSS animation events

CSS animation events

February 22, 2016

One of the perceived downsides of CSS animations is you can't do something else when an animation finishes. So you can't say once this CSS animation is over do something like show another animation or present a new previously hidden div.

Well, it turns out there are in fact three CSS animation related JS events: animationstart, animationiteration, and animationend. So what that means is there are events directly related to CSS animations that you can listen for in your javascript and do something once the animation starts, finishes, or an iteration completes.

Run this Pen to see animation-end in action.

See the Pen CSS Animation JS Events by Rich Finelli (@richfinelli) on CodePen.

Here’s the CSS for the animation for reference (excluding the keyframes which can be viewed in the above Pen).

.swim {
  animation-name: swim;
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-fill-mode: both;
}

If this is foreign to you, I wrote an article CSS Animations aren’t that tough that explains how easy it is to code an animation in CSS.

Next, in the JS, I’m listening for the animation to complete, and then removing the hide class from the h1. Here’s a breakdown of the JS:

//the element I am animating
var $striper = $("#striper");
//the function to show some HTML after the animation ends
function showSomeHTML() {
  $("h1").removeClass("hide");
}
// listening for the event and then calling the function
$striper.on("animationend", showSomeHTML);

animationend is like any other event. For instance, it could be “click”, “keyup”, “touchstart”, “load”, etc. What we’re doing is just waiting for the animation to end, and then showing a div.

The same idea can be used with animation animationstart.

See the Pen CSS Animation JS Events – animationstart by Rich Finelli (@richfinelli) on CodePen.

In this Pen, I have an animation delay of 3s in the animation CSS:

.swim {
  animation-name: swim;
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-delay: 3s; /*wait 3 seconds before starting the animation*/
}

So this allows me to have the text appear for 3 seconds prior to the animation starting. Once the animation starts, I have a function that hides the text. This way the space where the text was is clear for the fish to swim across the page unimpeded.

$striper.on({
  "animationstart": hideSomeHTML, //when animation starts
  "animationend": showSomeHTML //when animation ends
});

I also have another listener, again using animationend to show more text after the fish has completed its swim across the page. I don’t usually use this object syntax in jQuery, but for the animation start and end use case it is very convenient.

Finally, animationiteration can be useful as well. Here’s an example.

See the Pen CSS Animation JS Events – animationiteration by Rich Finelli (@richfinelli) on CodePen.

The only thing new in the CSS is adding an animation-iteration-count of 3 in order to be able to listen for the animationiteration event.

.swim {
  animation-name: swim;
  animation-duration: 3s;
  animation-timing-function: linear;
  animation-fill-mode: both;
  animation-delay: 3s;
  animation-iteration-count: 3; //iterate 3 times
}

In the JS, I’ve added another function countIteration and one more listener for animationiteration.

// the element I am animating
var $striper = $("#striper");

//the function to hide some HTML after the animation starts
function hideSomeHTML() {
  $("h1").addClass("hide");
  
}
var count = 0;
function countIteration() {
  count++;
  $(".iteration-count").text(count);
}
//the function to show some HTML after the animation ends
function showSomeHTML() {
  $("h1").removeClass("hide").text("that's it folks!");
  $(".iteration-count").text(3);
}

$striper.on({
  "animationstart": hideSomeHTML, //when animation starts
  "animationiteration": countIteration, //every time an iteration finishes
  "animationend": showSomeHTML //when animation ends
});

You can see that I’m using the same jQuery object syntax as I was before as now it’s even more convenient since all three events are attached to the same DOM element. I’ve also added the function that counts iterations. The animationiteration event fires when the iteration completes. So I have 3 iterations and expect the count variable to make it to 3. However it never makes it past 2. What happens is the animationiteration doesn’t fire on the last iteration, only the animationend event fires. So in order to get the text on the page to say, Iterations completed: 3 of 3 I have to manually set the text in the showSomeHTML function which is fired on animationend.

function showSomeHTML() {
  $("h1").removeClass("hide").text("that's it folks!");
  $(".iteration-count").text(3);
}

One thing to keep in mind

It’s worth pointing out that animation events fire for each animation-name property, not for each individual CSS property being animated. Might be obvious to you already, but I figured I’d mention it.

Browser support

Support for animation events are generally at the same level as support for CSS3 Animations as they’re part of the same specification. The key thing to keep in mind is that IE10 is the first version of Internet Explorer that supports them.

Other thoughts on animation events

Animation events seem pretty straightforward and not terribly difficult to use. Browser support is the main hurdle. The animation itself may not be core to your site or application, but doing something when an animation completes will more often than not be core functionality. Since Internet Explorer 10 is the first version of IE to support events, it makes it harder to justify using animation events in production. One work around is if the animation is triggered by JavaScript you could use a setTimeout() function that is set for the same amount of time as the animation’s duration. The downside of this approach is that it only works if the animation is triggered using Javascript. And, if the duration of the animation changes, you’ll have to update it in your CSS and in your JS.

Like CSS Animations, I think I’m going to save animation events for non-critical functionality. I’ll opt for VelocityJS, or another JS animation library, when I need to execute JS after an animation completes because of the deeper browser support. Just for comparison purposes, here’s how Velocity handles executing functionality when the animation ends.

$(".myDiv").velocity("transition.swoopIn", {
  complete: function() {
    //do something else...
  }
});

I’m doing an animation and when it completes, I can call another function. Deep browser support is a strong selling point. But, your adding another JS library that adds to the overall weight of your application.

The emerging web animations API

Just one final tidbit of information. There’s a native web animations API that is now in browsers like Chrome and Firefox. This has nothing to do with CSS animations and animation events but I was confused between the two things for a brief moment so I wanted to point this difference out. The web animations API is could be thought of as a native implementation of Velocity JS that leans heavily on CSS3 animations. To learn more about the web animation API check out Dan Wilson’s Creating a basic animation article as part of his very good series on web animations.

Mastering CSS: Book by Rich Finelli
Mastering CSS, the Book! Flexbox, Layout, Animations, Responsive, Retina, and more!
Mastering CSS, 2nd Edition, video course by Rich Finelli
Mastering CSS, Second Edition: 47 videos on how to make websites like a boss! Flexbox, Animations, Responsive, Retina, and more!
Back to top