SuperAPI AI Directory

web-animations

Design & creation

View repository

Updated 10-16 06:14

About this skill

Web Animations (WAAPI + CSS Transitions + CSS Animations)

Reference guide for the browser's 3 native animation APIs. Complements the skill view-transitions (navigation between states/pages — see ../view-transitions/SKILL.md).

When to Use Each API

Need API Why
Hover, focus, simple state CSS Transitions Declarative, zero JS
Pure CSS keyframe sequence CSS Animations @keyframes + animation
Runtime control (pause, reverse, seek) WAAPI Element.animate() returns Animation controllable
Scroll-driven reveal/parallax CSS animation-timeline or WAAPI ScrollTimeline Off main thread, no jank
Entry from display:none CSS Transitions + @starting-style + allow-discrete Native, no JS
Animation of height: auto CSS + interpolate-size Chrome 129+, progressive enhancement
Per-frame logic (physics, canvas) requestAnimationFrame Last resort, main thread only

Web Animations API (WAAPI)

Element.animate()

const anim = element.animate(
  [{ transform: 'translateX(0)', opacity: 1 }, { transform: 'translateX(300px)', opacity: 0 }],
  {
    duration: 300,          // milisegundos (NO segundos como CSS)
    easing: 'ease-out',     // default es 'linear' (distinto a CSS!)
    iterations: 1,          // Infinity para loops
    fill: 'forwards',       // none | forwards | backwards | both
    direction: 'alternate', // normal | reverse | alternate | alternate-reverse
    delay: 100,
    composite: 'replace',   // replace | add | accumulate
  }
);

Keyframes: array of objects (flexible, supports offset/easing per keyframe) or compact object ({ opacity: [0, 1] }). Implicit from/to: element.animate({ transform: 'translateX(300px)' }, 400) animates from the current value. Always camelCase (backgroundColor).

The Animation Object

// Playback
anim.play();  anim.pause();  anim.reverse();  anim.finish();  anim.cancel();
// Estado
anim.playState;    // 'idle' | 'running' | 'paused' | 'finished'
anim.currentTime;  // ms | null
anim.playbackRate; // 1.0 default, negativo = reversa
anim.updatePlaybackRate(0.5); // smooth rate change
// Promises (async/await)
await anim.ready;    // animacion arranco
await anim.finished; // animacion termino
// Events: onfinish, oncancel, onremove

Persist Styles (Prefer over fill:'forwards')

anim.finished.then(() => { anim.commitStyles(); anim.cancel(); });

fill: 'forwards' keeps memory and has side-effects on the cascade. commitStyles() writes the computed values to element.style and frees resources.

getAnimations()

element.getAnimations();  // del elemento (incluye CSS animations/transitions)
document.getAnimations(); // todas del documento

For advanced features (KeyframeEffect constructor, compositing, pseudo-element targeting), read references/waapi-advanced.md.

CSS Transitions

transition: opacity 200ms ease-out, transform 300ms cubic-bezier(0.34, 1.56, 0.64, 1);

@starting-style — Entry Animations

Without @starting-style, transitions do not trigger on the first render (there is no "before" state):

.card {
  opacity: 1; transform: translateY(0);
  transition: opacity 300ms, transform 300ms;
  @starting-style { opacity: 0; transform: translateY(8px); }
}

Animate display with allow-discrete

.dialog {
  display: none; opacity: 0;
  transition: opacity 200ms ease, display 200ms allow-discrete;
}
.dialog[open] { display: block; opacity: 1; }
@starting-style { .dialog[open] { opacity: 0; } }

Events: transitionend, transitionrun, transitionstart, transitioncancel. Gotcha: transitionend does NOT fire if interrupted.

CSS Animations

@keyframes slide-in {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0);     opacity: 1; }
}

.element {
  animation: slide-in 300ms ease-out forwards;
  /* name | duration | easing | fill-mode */

  /* Composicion con otras animaciones */
  animation-composition: add; /* replace | add | accumulate */
}

Events

element.addEventListener('animationend', (e: AnimationEvent) => {
  e.animationName; // nombre del @keyframes
});
// Tambien: animationstart, animationcancel, animationiteration

Performance

Compositor properties (GPU, always prefer): transform, opacity, filter, clip-path Main thread properties (avoid animating): width, height, top, left, background-color, box-shadow

CSS Animations and WAAPI run on the compositor for GPU properties. requestAnimationFrame always runs on the main thread.

will-change: apply only when the animation is imminent (e.g.: .card:hover { will-change: transform; }). Do not apply to everything — every promoted layer consumes GPU memory.

Layout thrashing: do not interleave reads (offsetHeight) and writes (style.height) in a loop. Batch reads first, then writes.

Scroll-Driven Animations

For scroll-driven animations (ScrollTimeline, ViewTimeline, animation-timeline, animation-range), read references/scroll-driven.md.

Modern Patterns

For interpolate-size, prefers-reduced-motion, @supports guards and other modern patterns, read references/patterns.md.

Gotchas

  1. WAAPI default easing is linear, not ease like CSS — always specify
  2. WAAPI duration in milliseconds, CSS in seconds — duration: 300 = 300ms
  3. fill: 'forwards' has side-effects — prefer commitStyles() + cancel()
  4. Transitions don't trigger without a previous state — use @starting-style or rAF delay
  5. transitionend doesn't fire if interrupted — don't rely on it as the only cleanup
  6. Compositor vs main thread — animate only transform, opacity, filter, clip-path
  7. will-change isn't free — each layer consumes GPU memory
  8. animation-duration: auto required for scroll-driven timelines in CSS

Browser Support (2025)

Feature Chrome Edge Firefox Safari
Element.animate() core 36+ 79+ 48+ 13.1+
commitStyles() / persist() 84+ 84+ 75+ 13.1+
@starting-style 117+ 117+ 129+ 17.5+
transition-behavior: allow-discrete 117+ 117+ 129+ 17.5+
Scroll-driven (CSS) 115+ 115+ flag 18+ (partial)
ScrollTimeline / ViewTimeline JS 115+ 115+ flag 18+ (partial)
interpolate-size 129+ 129+ No No

Pre-Deploy Checklist

[ ] prefers-reduced-motion implementado
[ ] Solo animar propiedades de compositor (transform, opacity, filter)
[ ] will-change aplicado selectivamente y removido post-animacion
[ ] Duraciones razonables (150-400ms transiciones, hasta 1s animaciones complejas)
[ ] @starting-style para entry animations
[ ] commitStyles() + cancel() en vez de fill:'forwards' persistente
[ ] Scroll-driven animations con @supports guard y fallback visible
[ ] Testeado en Chrome, Safari Y Firefox