vatt'ghern jaskier's ballads

Cookbook snippet · tier 2

Web Animations API

用 element.animate() 取得 CSS keyframes 之外更精確的時間控制。

Live example

build-12835

WAAPI 比純 CSS keyframes 多三件事:

  1. 即時控制狀態:.pause / .play / .cancel / .reverse
  2. .finished 是 Promise,可 await 串下一個動作。
  3. keyframes 是 JS array,參數可動態算出來。

點按鈕看 badge 動。prefers-reduced-motion 開時 duration 自動降 1ms。

完整食譜 (HTML + JS · 複製改寫用)

element.animate() for precise timing control beyond CSS keyframes. Returns an Animation object you can pause, reverse, or compose.

When to use

  • Sequence multiple property changes with custom easing per step
  • Pause/resume an animation imperatively (e.g., when reader scrolls away)
  • Animate properties CSS keyframes cannot reach (SVG pathLength, arbitrary attributes)

Complete snippet (paste-and-tweak)

<div class="vg-w-anim-EXAMPLE">
  <button id="vg-w-anim-EXAMPLE-go">animate</button>
  <svg viewBox="0 0 200 100">
    <circle id="vg-w-anim-EXAMPLE-dot" cx="20" cy="50" r="8" fill="var(--accent)" />
  </svg>
  <script>
    (function () {
      const root = document.querySelector('.vg-w-anim-EXAMPLE');
      const dot = root.querySelector('#vg-w-anim-EXAMPLE-dot');
      const btn = root.querySelector('#vg-w-anim-EXAMPLE-go');
      let animation = null;
      btn.addEventListener('click', () => {
        if (animation && animation.playState === 'running') {
          animation.pause();
          return;
        }
        animation = dot.animate([
          { cx: 20,  offset: 0 },
          { cx: 180, offset: 1 }
        ], {
          duration: 1200,
          easing: 'cubic-bezier(0.5, 0, 0.5, 1)',
          fill: 'forwards'
        });
        // Note: animating SVG attributes via WAAPI requires browser
        // support for the underlying attribute. cx works in current
        // Chromium/Firefox/Safari.
      });
    })();
  </script>
</div>

Gotchas

  • SVG attribute animation is supported but check the specific attribute. Numeric attributes (cx, cy, r, x1) generally work; complex attributes (d, transform) may need a CSS variable intermediate.
  • fill: 'forwards' keeps the end state after the animation finishes. Without it, the element snaps back.
  • animation.commitStyles() commits the current animated value to the inline style. Useful when you want to swap animations.
  • Cancellation: animation.cancel() returns the element to its pre-animation state; animation.finish() jumps to the end.