How to Capture CSS3 Animation Events in JavaScript

Craig Buckler

CSS3 animations are smooth and quick to implement but, unlike JavaScript, you don’t have frame-by-frame control. Fortunately, you can apply event handlers to any element to determine the animation state. This permits fine-grained control such as playing different animations in sequence.

Consider this simple CSS3 animation:

  -webkit-animation: flash 1s ease 3;
  -moz-animation: flash 1s ease 3;
  -ms-animation: flash 1s ease 3;
  -o-animation: flash 1s ease 3;
  animation: flash 1s ease 3;

/* animation */
@-webkit-keyframes flash {
  50% { opacity: 0; }

@-moz-keyframes flash {
  50% { opacity: 0; }

@-ms-keyframes flash {
  50% { opacity: 0; }

@-o-keyframes flash {
  50% { opacity: 0; }

@keyframes flash {
  50% { opacity: 0; }

When the enable class is applied to the element with ID anim, the animation named flash is run three times. Each iteration lasts one second during which the element fades out then in.

Three types of event are fired when the animation occurs:


var anim = document.getElementById("anim");
anim.addEventListener("animationstart", AnimationListener, false);

The animationstart event is fired when the animation starts for the first time.


anim.addEventListener("animationiteration", AnimationListener, false);

The animationiteration event is fired at the start of every new animation iteration, i.e. every iteration except the first.


anim.addEventListener("animationend", AnimationListener, false);

The animationend event is fired when the animation ends.

Browser Compatibility

At the time of writing, Firefox, Chrome, Safari, Opera and IE10 support CSS3 animation and the associated event handlers. In addition, Opera, IE10 and the webkit browsers use prefixes and throw in a few case changes for good measure…

W3C standard Firefox webkit Opera IE10
animationstart animationstart webkitAnimationStart oanimationstart MSAnimationStart
animationiteration animationiteration webkitAnimationIteration oanimationiteration MSAnimationIteration
animationend animationend webkitAnimationEnd oanimationend MSAnimationEnd

The easiest way around the prefix shenanigans is to call addEventListener for all prefixed and non-prefixed names using a custom function:

var pfx = ["webkit", "moz", "MS", "o", ""];
function PrefixedEvent(element, type, callback) {
	for (var p = 0; p code>

Cross-browser event handlers can now be assigned using a single line of code:

// animation listener events
PrefixedEvent(anim, "AnimationStart", AnimationListener);
PrefixedEvent(anim, "AnimationIteration", AnimationListener);
PrefixedEvent(anim, "AnimationEnd", AnimationListener);

The Event Object

In the code above, the AnimationListener function is called whenever an animation event occurs. An event object is passed as a single argument. As well as the standard properties and methods, it also provides:

  • animationName: the CSS3 animation name (i.e. flash)
  • elapsedTime: the time in seconds since the animation started.

We could therefore detect when the flash animation ends, e.g.

if (e.animationName == "flash" && 
    e.type.toLowerCase().indexOf("animationend") >= 0) {

The code could, for example, remove the existing class or apply another CSS3 animation in a specific sequence.

View the CSS3 Animation Events in JavaScript demonstration

The demonstration page displays a button. When it’s clicked, an “enable” class is toggled which starts the flash animation. The state is displayed in a console when an animation event fires. When the animation ends, the “enable” class is removed so the button can be clicked again.

Let me know if you use animation event capturing in any interesting projects.

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like HTML5 & CSS3 For the Real World.

Comments on this article are closed. Have a question about CSS? Why not ask it on our forums?