Introducing the Web Animations API

Good day, friends!

Web APIs are constantly evolving. Some of them, such as Console or Canvas, are well supported by all browsers, others are still under development.

One of the APIs under development is the Web Animations API or WAAPI. Despite the fact that the first version of the specification was published in 2012, and the API itself was first implemented in the Firefox and Chrome browsers in 2014, I found out about it recently (I have not heard about it before either - approx. Per.).

It allows developers to work with CSS animations using JavaScript. Its syntax is similar to the syntax of traditional CSS animations, but it has some features that make it easier for developers to create and modify animations.

Let's look at this API with a simple example.

Below we see a rotating square, the color of which changes with each turn.



CSS might look like this:

#cube {
    width: 40px;
    height: 40px;
    margin: 50%;
    background-color: pink;
    animation: rotateCube 1s infinite;
}

@keyframes rotateCube {
    0% {
        transform: rotate(0deg);
    }

    30% {
        background-color: purple;
    }

    100% {
        transform: rotate(180deg);
    }
}

Now do the same with WAAPI.

Create animation


It all starts with the creation of a Keyframes object containing information similar to that contained in the @keyframes directive of our CSS:

let cubeRotating = [
    {transform: 'rotate(0deg)', backgroundColor: 'pink'},
    {backgroundColor: 'purple', offset: 0.3},
    {transform: 'rotate(180deg)', backgroundColor: 'pink'}
]

We see two main differences:

  • We need to add backgroundColor to other steps.
  • We do not need to determine the time to complete each step as a percentage.

WAAPI automatically divides the animation into equal parts by the number of keys, so in our case the background color will change by about half of the animation.

However, we want this to happen by 30%, so we add the offset property with a value of 0.3 in the second step.

There is one important thing to remember: a Keyframes object must have at least two keys. Otherwise, a NotSupportedError will be thrown.

Next, an object is created containing animation properties that are responsible for the duration and number of repetitions:

let cubeTiming = {
    duration: 1000,
    iterations: Infinity
}

The duration of the animation is set in milliseconds.

Instead of “infinite” we use the keyword “Infinity”.

Finally, to run the animation, we use the Element.animate method:

document.getElementById('cube').animate(
    cubeRotating,
    cubeTiming
)

There are several more syntax options. Examples can be found here .

But that's not all. The fact is that with WAAPI we can control the playback of animations!

Animation Playback Control


Calling the animate method starts the animation immediately, but this is not always what we want. Therefore, we can call the pause and play methods to stop and start the animation, respectively:

let cubeAnimation = document.getElementById('cube').animate(
    cubeRotating,
    cubeTiming
)

cubeAnimation.pause()

document.body.onclick = () => cubeAnimation.play()

In our example, we work with one animation, but you can add several “animations” to the page and manage them as you like.

Among the available WAAPI methods, there are also finish, cancel, and reverse methods.

We can also control the playback speed of the animation:

let cubeAnimation = document.getElementById('cube').animate(
    cubeRotating,
    cubeTiming
)

document.body.onclick = () => cubeAnimation.playbackRate *= 1.5

This code makes the square rotate faster when clicked.



So far, we have been learning how to create one animation and control its playback. Another WAAPI feature is access to all animations at once.

Manage multiple animations


WAAPI has a getAnimations method that allows you to access all created animations.

Suppose we want to slow down all the animations that are on the page if the user has enabled prefers-reduced-motion (the CSS media function prefers-reduced-motion can be used to determine if the user has requested that the OS minimize the amount of animation or movement that it uses - approx.per.):

const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)')

if(mediaQuery.matches){
    document.getAnimations().forEach(animation => {
        animation.playbackRate *= 0.5
    })
}

In the example above, we are looking for the media function prefers-reduced-motion and, if its value is reduce, we get all the animations on the page and reduce their playback speed by half.

This is one of those things that make WAAPI very useful. We can make changes to several animations by changing one property.

Dependencies


Another interesting feature of WAAPI is the ability to determine the dependence of the properties of one animation on the properties of another.

For example, if we have two squares, and we want the second to rotate twice as fast as the first, we can do this in two ways.

First way:

let cube1Animation = document.getElementById('cube').animate(
    cubeRotating,
    {
        duration: 1000,
        iterations: Infinity
    }
)

let cube2Animation = document.getElementById('cube2').animate(
    cubeRotating,
    {
        duration: 500,
        iterations: Infinity
    }
)

The animation time of the first square is 1 second, the second - 500 milliseconds.

However, with this approach, when we change the animation time of the first square, we need to do the same for the second square.

Imagine how difficult it becomes when there are many animations or a large number of animated objects?

The best way to solve our problem is to establish the dependence of the rotation of the second square on the first:

let cube1Animation = document.getElementById('cube').animate(
    cubeRotating,
    {
        duration: 1000,
        iterations: Infinity
    }
)

let cube2Animation = document.getElementById('cube2').animate(
    cubeRotating,
    {
        duration: cube1Animation.effect.timing.duration / 2,
        iterations: Infinity
    }
)

Thus, we use the animation time of the first square to determine the animation time of the second square. Now, when changing the animation time of the first square, the second will always rotate twice as fast!



Performance


Speaking of performance, I did not notice much difference between using CSS and WAAPI. But this may be due to the simplicity of my example.

One important advantage of WAAPI over other methods of creating animation in JS is that it runs in a separate thread, which allows the main thread to "forget" about the animation and do the rest of the code.

Browser support


WAAPI is currently in draft status and is partially supported in recent versions of Firefox and Chrome, as well as in major mobile browsers.

Partial support means browsers support methods such as play, pause, reverse, finish and playbackRate, but do not support getAnimations.



There is a polyphile for WAAPI in all browsers.

That's all for me!

Further reading:

Using the Web Animations API
Web Animations API examples
Great series “Let's talk about the Web Animations API” by Dan Wilson

Thank you for your attention.

Source: https://habr.com/ru/post/undefined/


All Articles