CSS + the Web Animations API

As of this writing, the features discussed are in the latest stable versions of Firefox (75) and Safari (version 13.1, iOS 13.4). They are also in Edge and Chrome with the Experimental Web Platform Features flag enabled. Please view this article in a supported browser to see the live demos.

While the Web Animations API initially brought a similar mechanism as CSS animations to JavaScript, it also added a few additional features like modifying playback rate and jumping to different points in an animation’s timeline. As the final pieces of the Web Animations Level 1 specification roll out to browsers, it’s not just JavaScript that gets extra features.

Getting all Web Animations with the API

One of the newer pieces now available is the ability to get references to all the animations for a specific element or even a full document. A reference to an animation is key to be able to update the animation later or set listeners for events.

//returns an array of all active animations contained within the document
document.getAnimations();

//returns an array of all active animations for a specific element
document.getElementById('header').getAnimations()

//returns an array of all active animations for a specific element and its descendants
document.getElementById('header').getAnimations({subtree: true})

When called on the document, every active animation on your page will be returned.

When called on an element, by default you will get all the active animations on that specific element. You can also specify an options object parameter with the property subtree enabled if you want to see all the animations for a given element and every element it contains as a descendant.

The best part is that this new Web Animations API method does not just return animations that were created with the Web Animations API, but also CSS Animations and CSS Transitions. Any API method can then be called on the CSS animations and transitions as though it had been created by the API.

How do I know where an animation was created?

Each animation that appears in the getAnimations() array today will be of type Animation, CSSAnimation, or CSSTransition. The two CSS ones extend the Animation interface.

This means each type will have the normal Web Animations API methods, but the two CSS ones will have an extra property that are specific to those needs.

See the Pen WAAPI: Check if an Animation is from the WAAPI by Dan Wilson (@danwilson) on CodePen.

CSS Animations will have a property called animationName that will expose the animation name (the same that appears in the CSS animation-name and the @keyframes definition). CSS Transitions will similarly have transitionProperty to share which property it is responsible for transitioning.

const animations = document.getAnimations();

// Iterate through each animation to inspect
animations.forEach(animation => {
  if (animation.animationName) {
    // CSS Animation with the specified name
  } else if (animation.transitionProperty) {
    // CSS Transition on the specified property
  } else {
    // Web Animations API
  }
});

That leaves all the rest as ones from the Web Animations API (though, SVG Animations are mentioned in the specification as also making it in here one day). If you need to know which WAAPI animation is which, you can look at the keyframes or timing options, or specify an id at creation which is returned back.

Extending CSS Animations with the Web Animations API

Since all these animations share a common interface and have the same underlying engine behind them (one of the main goals of the Web Animations specification), we can now use the API to interact with our CSS animations.

See the Pen HyperCSS by Dan Wilson (@danwilson) on CodePen.

For browsers that do not support getAnimations(), a simple button that allows the user to start or pause a CSS animation appears. However, with the ability to grab these animations from the API in supported browsers, a range slider is swapped in that allows the user to vary the playback rate of the CSS animations. This happens because the API has the updatePlaybackRate() that allows us to speed up or slow down an animation, and our CSS Animations can now leverage this feature (there is a known bug in Webkit, however, so playback rate in Safari does not update as of this writing). We can also jump to (or read) specific points in our animation timeline through the currentTime read/write property, and we can read or update the specific keyframes or timing options (such as duration, delay, and iterations).

There are also more direct ways to cancel or finish an animation. With CSS animations, you could always update the style.animationName = 'none' in JavaScript, but now you can also call cancel() on the animation. CSS animations and transitions have long had solid JavaScript event listeners for animationend, transitionstart, and others, so the Web Animations API does not bring much new here. That said, the WAAPI offers comparable callbacks and Promises if those are preferred.

And if you want to get a sneak preview of the next ways that the API will be extending capabilities, check out Firefox Nightly to see additive animation in action.