How to Capture CSS3 Animation Events in JavaScript
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:
#anim.enable
{
-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:
animationstart
var anim = document.getElementById("anim");
anim.addEventListener("animationstart", AnimationListener, false);
The animationstart event is fired when the animation starts for the first time.
animationiteration
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.
animationend
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 < pfx.length; p++) {
if (!pfx[p]) type = type.toLowerCase();
element.addEventListener(pfx[p]+type, callback, false);
}
}
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.
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.
Source Link: http://www.sitepoint.com/css3-animation-javascript-event-handlers/