DEV Community

Weather Clock Dash
Weather Clock Dash

Posted on

CSS Animations and Web Animations API: From Transitions to Full Control

CSS animations let you add motion to your pages without JavaScript. Firefox has excellent support for both CSS animations and the Web Animations API, and DevTools includes an animation inspector that makes debugging smooth.

CSS Transitions

Transitions animate property changes when a trigger fires (hover, class change, focus):

/* Smooth hover effect */
.button {
  background-color: #3B82F6;
  transform: translateY(0);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
  transition: background-color 0.2s ease,
              transform 0.15s ease,
              box-shadow 0.15s ease;
}

.button:hover {
  background-color: #2563EB;
  transform: translateY(-2px);
  box-shadow: 0 4px 12px rgba(37, 99, 235, 0.3);
}
Enter fullscreen mode Exit fullscreen mode

Transition shorthand: transition: property duration timing-function delay

/* Multiple transitions */
transition: color 0.2s ease, opacity 0.3s ease 0.1s;
/*                                                ^ delay */
Enter fullscreen mode Exit fullscreen mode

CSS Animation (@keyframes)

For looping or complex multi-step animations:

@keyframes spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes pulse {
  0%, 100% { transform: scale(1); opacity: 1; }
  50%       { transform: scale(1.05); opacity: 0.8; }
}

@keyframes slideIn {
  from {
    opacity: 0;
    transform: translateX(-20px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

.spinner {
  animation: spin 1s linear infinite;
}

.notification {
  animation: slideIn 0.3s ease-out both;
}
Enter fullscreen mode Exit fullscreen mode

Animation properties:

.element {
  animation-name: slideIn;
  animation-duration: 0.3s;
  animation-timing-function: ease-out;
  animation-delay: 0.1s;
  animation-iteration-count: 1;      /* or: infinite */
  animation-direction: normal;       /* or: reverse, alternate, alternate-reverse */
  animation-fill-mode: both;         /* or: none, forwards, backwards */
  animation-play-state: running;     /* or: paused */

  /* Shorthand */
  animation: slideIn 0.3s ease-out 0.1s 1 normal both;
}
Enter fullscreen mode Exit fullscreen mode

Timing Functions

The timing function controls the animation curve:

animation-timing-function: linear;          /* constant speed */
animation-timing-function: ease;            /* slow-fast-slow (default) */
animation-timing-function: ease-in;         /* slow start */
animation-timing-function: ease-out;        /* slow end */
animation-timing-function: ease-in-out;     /* slow both ends */
animation-timing-function: cubic-bezier(0.34, 1.56, 0.64, 1); /* spring */
animation-timing-function: steps(4, end);   /* discrete steps */
Enter fullscreen mode Exit fullscreen mode

Firefox DevTools shows a visual curve editor when you click a timing function value.

The will-change Property

Hint to the browser that an element will animate — allows GPU compositing:

.animated-element {
  will-change: transform, opacity;
}

/* Remove after animation to free GPU memory */
.animated-element.animation-done {
  will-change: auto;
}
Enter fullscreen mode Exit fullscreen mode

Use sparingly — every will-change element gets its own compositor layer.

Web Animations API

For programmatic animation control, use the Web Animations API (WAAPI):

// Same as CSS: @keyframes + animation
const element = document.querySelector('.box');

const animation = element.animate([
  { transform: 'translateX(0)', opacity: 1 },
  { transform: 'translateX(200px)', opacity: 0.5 },
  { transform: 'translateX(400px)', opacity: 1 },
], {
  duration: 1000,
  easing: 'ease-in-out',
  iterations: Infinity,
  direction: 'alternate',
  fill: 'both',
});

// Control playback
animation.pause();
animation.play();
animation.reverse();
animation.cancel();

// Synchronize multiple animations
const a1 = el1.animate([...], { duration: 500 });
const a2 = el2.animate([...], { duration: 500, delay: 250 });

// Wait for animations to finish
await Promise.all([a1.finished, a2.finished]);
console.log('All done');
Enter fullscreen mode Exit fullscreen mode

Firefox Animation Inspector

Firefox DevTools has a dedicated Animation panel:

  1. Open DevTools (F12)
  2. Click the Animations tab (or find it under the three-dot menu)
  3. The timeline shows all animations on the page
  4. Click any animation to inspect its keyframes
  5. Drag the scrubber to step through frames
  6. Click an animation name to jump to the element in the DOM

This makes debugging "why is my animation janky?" much easier — you can see exactly when each keyframe fires and the computed easing curve.

Performance: Animating the Right Properties

Only animate these properties for smooth 60fps — they run on the GPU compositor:

/* GPU-composited: fast */
transform: translate(), scale(), rotate(), skew()
opacity
filter (in most cases)

/* NOT composited: triggers layout (slow) */
width, height, top, left, margin, padding, border
font-size, line-height
Enter fullscreen mode Exit fullscreen mode
/* Slow: animates a layout property */
.bad {
  transition: height 0.3s ease;
}

/* Fast: animate transform instead */
.good {
  transform-origin: top;
  transition: transform 0.3s ease;
}
.good.collapsed {
  transform: scaleY(0);
}
Enter fullscreen mode Exit fullscreen mode

Reduced Motion Accessibility

Always respect the user's preference:

/* Default: animate freely */
.animated {
  animation: spin 2s linear infinite;
}

/* Reduced motion: disable or simplify */
@media (prefers-reduced-motion: reduce) {
  .animated {
    animation: none;
  }

  /* Or keep a subtle version */
  .animated {
    animation-duration: 10s; /* much slower */
  }
}
Enter fullscreen mode Exit fullscreen mode
// Check in JavaScript
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;

if (!prefersReduced) {
  element.animate([...], { duration: 300 });
} else {
  element.classList.add('target-state'); // instant change
}
Enter fullscreen mode Exit fullscreen mode

Firefox users can set this preference in Settings → General → Reduce animations.

CSS Custom Properties in Animations

:root {
  --animation-duration: 0.3s;
  --animation-delay: 0s;
}

.card {
  animation: slideIn var(--animation-duration) ease var(--animation-delay) both;
}

/* Stagger children */
.card:nth-child(1) { --animation-delay: 0.0s; }
.card:nth-child(2) { --animation-delay: 0.1s; }
.card:nth-child(3) { --animation-delay: 0.2s; }
.card:nth-child(4) { --animation-delay: 0.3s; }
Enter fullscreen mode Exit fullscreen mode

CSS custom properties can be set in JavaScript too:

card.style.setProperty('--animation-delay', `${index * 0.1}s`);
Enter fullscreen mode Exit fullscreen mode

Top comments (0)