DEV Community

Tianya School
Tianya School

Posted on

Web Animations API Native Browser Support for Smooth Animations

Web Animations API, a powerful browser-native tool for creating smooth and dynamic animations using pure JavaScript, without relying on CSS or third-party libraries. Compared to CSS animations, the Web Animations API offers greater flexibility, enabling dynamic control like pausing, reversing, and seamless integration with JavaScript logic.

What is the Web Animations API?

The Web Animations API is a native JavaScript API based on W3C standards, designed for creating and controlling animations. It combines the smoothness of CSS animations with the flexibility of JavaScript, allowing precise manipulation of element properties like position, color, and opacity. Key features include:

  • Native Support: No external libraries needed, supported by modern browsers (Chrome, Firefox, Safari, etc.).
  • Fine-Grained Control: Dynamically modify animation parameters, pause, play, reverse, or adjust speed.
  • High Performance: Runs off the main thread (compositor thread), as smooth as CSS animations.
  • CSS/JavaScript Integration: Manipulates CSS properties and integrates with events and data binding.
  • Composability: Supports multi-segment animations, timelines, sequential, and parallel animations.

We’ll start with basic animations and progress to complex scenarios, integrating with React and Vue for practical applications.

Environment Setup

The Web Animations API is built into browsers, requiring no libraries, but we need a simple development environment. Create an HTML project:

mkdir web-animations-demo
cd web-animations-demo
touch index.html
Enter fullscreen mode Exit fullscreen mode

Install a local server (e.g., live-server):

npm install -g live-server
Enter fullscreen mode Exit fullscreen mode

Directory structure:

web-animations-demo/
├── index.html
├── style.css
├── script.js
Enter fullscreen mode Exit fullscreen mode

Run live-server and visit localhost:8080. We’ll use plain HTML/CSS/JS for animations, later adding React and Vue.

Basic Animation: Movement and Scaling

The core of the Web Animations API is Element.animate(), which takes keyframes and options. Create a simple movement animation.

index.html:

<!DOCTYPE html>
<html>
<head>
  <title>Web Animations API Demo</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div class="box"></div>
  <script src="script.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

style.css:

.box {
  width: 100px;
  height: 100px;
  background: #007bff;
  position: absolute;
  top: 50px;
  left: 50px;
}
Enter fullscreen mode Exit fullscreen mode

script.js:

const box = document.querySelector('.box');

box.animate(
  [
    { transform: 'translateX(0)' },
    { transform: 'translateX(300px)' }
  ],
  {
    duration: 1000,
    easing: 'ease-in-out',
    iterations: Infinity,
    direction: 'alternate'
  }
);
Enter fullscreen mode Exit fullscreen mode

Run live-server. A blue box moves back and forth along the X-axis. Code breakdown:

  • animate() takes two arguments: an array of keyframes (like CSS keyframes) and a configuration object.
  • Keyframes define animation states, with transform: translateX controlling X-axis movement.
  • Options:
    • duration: Animation length in milliseconds.
    • easing: Easing function, ease-in-out for smooth transitions.
    • iterations: Number of loops, Infinity for infinite looping.
    • direction: alternate for back-and-forth playback.

Controlling Animations

animate() returns an Animation object, allowing pause, play, or reverse. Update script.js:

const box = document.querySelector('.box');

const animation = box.animate(
  [
    { transform: 'translateX(0) scale(1)' },
    { transform: 'translateX(300px) scale(1.5)' }
  ],
  {
    duration: 1000,
    easing: 'ease-in-out',
    iterations: Infinity,
    direction: 'alternate'
  }
);

document.addEventListener('click', () => {
  if (animation.playState === 'running') {
    animation.pause();
  } else {
    animation.play();
  }
});
Enter fullscreen mode Exit fullscreen mode

Click the page to pause/resume the animation, which now includes scaling. Animation object methods:

  • play(): Starts the animation.
  • pause(): Pauses the animation.
  • playState: Current state (running, paused, etc.).
  • reverse(): Reverses playback.

Multi-Property Animation

The Web Animations API supports animating multiple properties, like color, opacity, and size. Update script.js:

const box = document.querySelector('.box');

const animation = box.animate(
  [
    {
      transform: 'translateX(0) scale(1)',
      backgroundColor: '#007bff',
      opacity: 1
    },
    {
      transform: 'translateX(300px) scale(1.5)',
      backgroundColor: '#ff5733',
      opacity: 0.5
    }
  ],
  {
    duration: 1500,
    easing: 'ease-in-out',
    iterations: Infinity,
    direction: 'alternate'
  }
);
Enter fullscreen mode Exit fullscreen mode

The box moves, changes from blue to orange, and fades opacity from 1 to 0.5. Keyframes support any CSS property (in camelCase, e.g., backgroundColor).

Dynamic Keyframes

Generate keyframes dynamically with JavaScript. Update script.js:

const box = document.querySelector('.box');

let distance = 300;
const keyframes = [
  { transform: `translateX(0) scale(1)`, backgroundColor: '#007bff' },
  { transform: `translateX(${distance}px) scale(1.5)`, backgroundColor: '#ff5733' }
];

const animation = box.animate(keyframes, {
  duration: 1500,
  easing: 'ease-in-out',
  iterations: Infinity,
  direction: 'alternate'
});

document.addEventListener('keydown', e => {
  if (e.key === 'ArrowRight') {
    distance += 50;
    const newKeyframes = [
      { transform: `translateX(0) scale(1)`, backgroundColor: '#007bff' },
      { transform: `translateX(${distance}px) scale(1.5)`, backgroundColor: '#ff5733' }
    ];
    box.animate(newKeyframes, {
      duration: 1500,
      easing: 'ease-in-out',
      iterations: Infinity,
      direction: 'alternate'
    });
  }
});
Enter fullscreen mode Exit fullscreen mode

Press the right arrow key to increase the movement distance. animate() replaces the old animation with new dynamically generated keyframes, showcasing flexibility.

Sequential and Parallel Animations

The Web Animations API supports sequential and parallel animations. Create a sequential animation.

Update index.html:

<div class="box"></div>
<div class="box" style="top: 200px;"></div>
Enter fullscreen mode Exit fullscreen mode

Update script.js:

const boxes = document.querySelectorAll('.box');

boxes.forEach((box, index) => {
  box.animate(
    [
      { transform: 'translateX(0)' },
      { transform: 'translateX(300px)' }
    ],
    {
      duration: 1000,
      delay: index * 500,
      easing: 'ease-in-out',
      iterations: Infinity,
      direction: 'alternate'
    }
  );
});
Enter fullscreen mode Exit fullscreen mode

Two boxes move sequentially, with the second starting 500ms later due to delay: index * 500. Remove delay for parallel animations.

Timeline Control

Use Animation’s startTime and currentTime for timeline control. Update script.js:

const box = document.querySelector('.box');

const animation = box.animate(
  [
    { transform: 'translateX(0)', opacity: 1 },
    { transform: 'translateX(300px)', opacity: 0.5 }
  ],
  {
    duration: 2000,
    easing: 'ease-in-out',
    iterations: 1
  }
);

document.addEventListener('click', () => {
  animation.currentTime = 0; // Reset to start
  animation.play();
});
Enter fullscreen mode Exit fullscreen mode

Click to restart the animation. currentTime sets the animation progress in milliseconds.

Animation Events

The Web Animations API supports event listeners for events like completion or cancellation. Update script.js:

const box = document.querySelector('.box');

const animation = box.animate(
  [
    { transform: 'translateX(0)', opacity: 1 },
    { transform: 'translateX(300px)', opacity: 0.5 }
  ],
  {
    duration: 1000,
    iterations: 1
  }
);

animation.onfinish = () => {
  console.log('Animation finished!');
  box.style.transform = 'translateX(300px)';
  box.style.opacity = '0.5';
};

animation.oncancel = () => {
  console.log('Animation cancelled!');
};

document.addEventListener('click', () => {
  if (animation.playState === 'running') {
    animation.cancel();
  } else {
    animation.play();
  }
});
Enter fullscreen mode Exit fullscreen mode

The animation logs “Animation finished!” on completion and “Animation cancelled!” on cancellation. onfinish applies final styles to prevent flickering.

Using in React

Use the Web Animations API in React. Create a React project:

npx create-react-app react-animations
cd react-animations
Enter fullscreen mode Exit fullscreen mode

Update src/App.js:

import { useRef, useEffect } from 'react';
import './App.css';

function App() {
  const boxRef = useRef(null);

  useEffect(() => {
    const box = boxRef.current;
    const animation = box.animate(
      [
        { transform: 'translateX(0)', backgroundColor: '#007bff' },
        { transform: 'translateX(300px)', backgroundColor: '#ff5733' }
      ],
      {
        duration: 1000,
        easing: 'ease-in-out',
        iterations: Infinity,
        direction: 'alternate'
      }
    );

    return () => animation.cancel(); // Cleanup
  }, []);

  return (
    <div style={{ padding: 20 }}>
      <h1>React Animation</h1>
      <div ref={boxRef} className="box"></div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

src/App.css:

.box {
  width: 100px;
  height: 100px;
  background: #007bff;
  position: absolute;
  top: 50px;
}
Enter fullscreen mode Exit fullscreen mode

Run npm start. The box moves and changes color. useRef accesses the DOM element, useEffect runs the animation, and cleanup cancels it to prevent memory leaks.

Dynamic Control

Add interactive control:

import { useRef, useEffect, useState } from 'react';
import './App.css';

function App() {
  const boxRef = useRef(null);
  const [isPlaying, setIsPlaying] = useState(true);

  useEffect(() => {
    const box = boxRef.current;
    const animation = box.animate(
      [
        { transform: 'translateX(0)', backgroundColor: '#007bff' },
        { transform: 'translateX(300px)', backgroundColor: '#ff5733' }
      ],
      {
        duration: 1000,
        easing: 'ease-in-out',
        iterations: Infinity,
        direction: 'alternate'
      }
    );

    if (!isPlaying) animation.pause();

    return () => animation.cancel();
  }, [isPlaying]);

  return (
    <div style={{ padding: 20 }}>
      <h1>React Animation</h1>
      <div ref={boxRef} className="box"></div>
      <button onClick={() => setIsPlaying(!isPlaying)}>
        {isPlaying ? 'Pause' : 'Play'}
      </button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Click the button to toggle the animation. useEffect updates based on isPlaying.

Using in Vue

Use the Web Animations API in Vue. Create a Vue project:

vue create vue-animations
cd vue-animations
Enter fullscreen mode Exit fullscreen mode

Update src/App.vue:

<template>
  <div style="padding: 20px;">
    <h1>Vue Animation</h1>
    <div ref="box" class="box"></div>
    <button @click="toggleAnimation">{{ isPlaying ? 'Pause' : 'Play' }}</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      isPlaying: true,
      animation: null
    };
  },
  mounted() {
    this.animation = this.$refs.box.animate(
      [
        { transform: 'translateX(0)', backgroundColor: '#007bff' },
        { transform: 'translateX(300px)', backgroundColor: '#ff5733' }
      ],
      {
        duration: 1000,
        easing: 'ease-in-out',
        iterations: Infinity,
        direction: 'alternate'
      }
    );
  },
  methods: {
    toggleAnimation() {
      this.isPlaying = !this.isPlaying;
      if (this.isPlaying) {
        this.animation.play();
      } else {
        this.animation.pause();
      }
    }
  },
  beforeUnmount() {
    this.animation.cancel();
  }
};
</script>

<style>
.box {
  width: 100px;
  height: 100px;
  background: #007bff;
  position: absolute;
  top: 50px;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Run npm run serve. The box animates, and clicking the button pauses/plays it. ref accesses the DOM, and beforeUnmount cleans up the animation.

Complex Scenario: Interactive Animation

Create a draggable animation with the Web Animations API.

Update index.html:

<div class="box" id="draggable"></div>
Enter fullscreen mode Exit fullscreen mode

Update style.css:

.box {
  width: 100px;
  height: 100px;
  background: #007bff;
  position: absolute;
  top: 50px;
  left: 50px;
  cursor: move;
}
Enter fullscreen mode Exit fullscreen mode

Update script.js:

const box = document.getElementById('draggable');
let isDragging = false;
let startX, startY;

box.addEventListener('mousedown', e => {
  isDragging = true;
  startX = e.clientX - startX;
  startY = e.clientY - startY;
});

document.addEventListener('mousemove', e => {
  if (!isDragging) return;
  const x = e.clientX - startX;
  const y = e.clientY - startY;
  box.animate(
    [
      { transform: `translate(${x}px, ${y}px)` }
    ],
    { duration: 0, fill: 'forwards' }
  );
});

document.addEventListener('mouseup', () => {
  isDragging = false;
});

box.animate(
  [
    { transform: 'scale(1)', backgroundColor: '#007bff' },
    { transform: 'scale(1.2)', backgroundColor: '#ff5733' }
  ],
  {
    duration: 1000,
    iterations: Infinity,
    direction: 'alternate'
  }
);
Enter fullscreen mode Exit fullscreen mode

Dragging updates the box’s position in real-time, and releasing the mouse resumes the scale and color animation. fill: 'forwards' persists the dragged position.

Real-World Scenario: E-commerce Product Card

Create a product card with hover animations.

Update index.html:

<div class="product-card">
  <img src="https://via.placeholder.com/150" alt="Product" />
  <h2>Product Name</h2>
  <p>$99.99</p>
</div>
Enter fullscreen mode Exit fullscreen mode

Update style.css:

.product-card {
  width: 200px;
  padding: 20px;
  border: 1px solid #ccc;
  border-radius: 8px;
  text-align: center;
}

img {
  width: 100%;
}
Enter fullscreen mode Exit fullscreen mode

Update script.js:

const card = document.querySelector('.product-card');
const img = card.querySelector('img');

card.addEventListener('mouseenter', () => {
  img.animate(
    [
      { transform: 'scale(1)', opacity: 1 },
      { transform: 'scale(1.1)', opacity: 0.8 }
    ],
    {
      duration: 300,
      easing: 'ease-out',
      fill: 'forwards'
    }
  );
});

card.addEventListener('mouseleave', () => {
  img.animate(
    [
      { transform: 'scale(1.1)', opacity: 0.8 },
      { transform: 'scale(1)', opacity: 1 }
    ],
    {
      duration: 300,
      easing: 'ease-out',
      fill: 'forwards'
    }
  );
});
Enter fullscreen mode Exit fullscreen mode

Hovering scales and fades the image; moving away reverses it. The short animation enhances interactivity.

Conclusion (Technical Details)

The Web Animations API enables flexible, high-performance browser animations. The examples demonstrated:

  • Basic movement, scaling, and color animations.
  • Dynamic keyframes and controls (pause, play, reverse).
  • Sequential and parallel animations.
  • Integration with React and Vue.
  • Interactive drag and e-commerce card animations.

Run these examples, inspect frame rates and performance in DevTools, and experience the smoothness of the Web Animations API!

Top comments (0)