Web Animations API Tutorial Part 1: Creating a Basic Animation

This is Part 1 of an introductory/tutorial series on the Web Animations API coming to browsers. I've updated the series content in June 2016, as Chrome and Firefox have both rolled out major updates (and some small spec changes). If you have thoughts/questions or see that I’ve misinterpreted the spec, please reach out to me on Twitter, @dancwilson.

We’ve taken our initial look at the Web Animations API, but we didn’t get into any real specifics… so let’s dive in now.

The WAAPI gives you more control than you might be used to with CSS Animations, but before we get into these extras, we need to set up the baseline: How do I create a basic animation through this API?

Creating a Keyframe Animation

If you are familiar with CSS Transitions and/or animations this will look familiar.

var player = document.getElementById('toAnimate').animate([
    { transform: 'scale(1)', opacity: 1, offset: 0 },
    { transform: 'scale(.5)', opacity: .5, offset: .3 },
    { transform: 'scale(.667)', opacity: .667, offset: .7875 },
    { transform: 'scale(.6)', opacity: .6, offset: 1 }
  ], {
    duration: 700, //milliseconds
    easing: 'ease-in-out', //'linear', a bezier curve, etc.
    delay: 10, //milliseconds
    iterations: Infinity, //or a number
    direction: 'alternate', //'normal', 'reverse', etc.
    fill: 'forwards' //'backwards', 'both', 'none', 'auto'
  });

For comparison’s sake, here is an equivalent CSS Keyframe animation

@keyframes emphasis {
  0% {
    transform: scale(1); 
    opacity: 1; 
  }
  30% {
    transform: scale(.5); 
    opacity: .5; 
  }
  78.75% {
    transform: scale(.667); 
    opacity: .667; 
  }
  100% {
    transform: scale(.6);
    opacity: .6; 
  }
}
#toAnimate {
  animation: emphasis 700ms ease-in-out 10ms infinite alternate forwards;
}

We’ll break this down and explain each piece.

var player = document.getElementById('toAnimate').animate()

Animating will return an Animation (formerly known in the spec as an AnimationPlayer) that will let us do fun things later, so you’ll likely want to set up a variable to capture this reference. We find the element we want to animate (here simply with document.getElementById) and call the animate function. This function is newly added with the spec, so you will either want to test it for support/existence before using it or include the polyfill.

The animate function takes two parameters, an array of KeyframeEffects and AnimationEffectTimingProperties options. Essentially the first parameter maps to what you would put in the CSS @keyframes, and the second parameter is what you would specify with the animation-* properties (or the animation shorthand, as in my earlier example) in your CSS rules. The key benefit here is that we can use variables or reuse previously defined KeyframeEffects, whereas with CSS we’re limited to the values we declare upfront.

var player = document.getElementById('toAnimate').animate([
    { transform: 'scale(1)', opacity: 1 },
    { transform: 'scale(.5)', opacity: .5 },
    { transform: 'scale(.667)', opacity: .667 },
    { transform: 'scale(.6)', opacity: .6 }
  ]);

For each KeyframeEffect, we change the percentage offsets we have in CSS to a decimal offset value from 0 to 1. It is optional though, and if you don’t specify any they will be evenly distributed (so if you have three, the first has an offset of 0, the second has an offset of .5, and the third offset = 1). You can also specify an easing property that is the same as the animation-timing-function in CSS. The other properties in each KeyframeEffect are the properties to animate. The values for each property should match how you would specify them in JavaScript using element.style, so opacity will be a number, but transform will expect a string.

var player = document.getElementById('toAnimate').animate([], {
    duration: 700, //milliseconds
    easing: 'ease-in-out', //'linear', a bezier curve, etc.
    delay: 10, //milliseconds
    iterations: Infinity, //or a number
    direction: 'alternate', //'normal', 'reverse', etc.
    fill: 'forwards' //'backwards', 'both', 'none', 'auto'
  });

The timing properties will map to CSS animation properties, though sometimes with different names. The earlier code sample discusses the primary options.

Here is an example that uses the polyfill (but if you are viewing in Chrome 36+, Opera 23+, or Firefox 48+ it should be using the actual browser implementation). The first column grey blocks are animating with the WAAPI, and the second column red blocks are animating with CSS keyframes.

See the Pen CSS Keyframes v. WAAPI by Dan Wilson (@danwilson) on CodePen.

Next Time…

Now that we know how to make an equivalent animation from what we know in CSS, we’ll start looking at the Animation object that the animate function returns. This is where we see the real features and improvements.

Check out the rest of this series: