Web Animations APIでここまでできる。依存なしで始めるUIモーション

はじめに

アニメーション導入の最初の悩みは「ライブラリを入れるべきか」です。案件によっては依存を増やしづらく、まず標準APIでどこまで対応できるかを知っておく必要があります。

Web Animations API は、モーダルやカード表示のような中小規模のUI演出に十分使えます。この記事では、基本の表示制御から実務で使うキャンセル処理・連打対策までを整理します。

使い方

Web Animations API はブラウザ標準のAPIで、element.animate() を中心にアニメーションを記述します。キーフレーム、duration、easing、再生制御をJavaScript側で扱えるのが特徴です。

実務での強みは、導入コストが低いことです。既存画面へ「小さな演出」だけ追加したいときに、依存パッケージを増やさず進められます。

最小例として、ボタンクリックでパネルを開く実装を作ります。hidden の切り替え順と finished の完了待ちを押さえると安定します。

See the Pen Web Animations API by watanabe (@web-sourcecode) on CodePen.

HTML

HTML
<button id="js-open" type="button">設定を開く</button>
<div id="js-panel" class="panel" hidden>
  <p>通知設定を変更できます。</p>
</div>

CSS

CSS
.panel {
  width: min(360px, 100%);
  padding: 16px;
  border-radius: 12px;
  background: #fff;
  border: 1px solid #e2e8f0;
  box-shadow: 0 8px 24px rgb(0 0 0 / 12%);
}

JavaScript

JavaScript
const panel = document.getElementById("js-panel")
const open = document.getElementById("js-open")

open.addEventListener("click", async () => {
  panel.hidden = false
  const anim = panel.animate(
    [
      { opacity: 0, transform: "translateY(10px) scale(.98)" },
      { opacity: 1, transform: "translateY(0) scale(1)" }
    ],
    { duration: 240, easing: "cubic-bezier(.22,.61,.36,1)", fill: "both" }
  )
  await anim.finished
})

Web Animations API は、管理画面の開閉UI、フィルター適用後のカード再描画、トースト通知などで扱いやすいです。規模が小さい画面ほど、標準APIだけで十分なことが多いです。

また、既存コードへ段階導入しやすい点も実務向けです。必要な箇所だけ animate() に置き換え、効果検証しながら広げられます。

応用コード

次は「開く/閉じる」「連打対策」「reduced motion 対応」を含む実装です。

See the Pen Web Animations API 2 by watanabe (@web-sourcecode) on CodePen.

HTML

HTML
<button id="js-toggle" type="button" aria-expanded="false">詳細を表示</button>
<section id="js-detail" hidden>
  <p>ここに詳細情報を表示します。</p>
</section>

JavaScript

JavaScript
const toggle = document.getElementById("js-toggle")
const detail = document.getElementById("js-detail")
const prefersReduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches

let isAnimating = false

async function openDetail() {
  detail.hidden = false
  const duration = prefersReduced ? 1 : 220
  const anim = detail.animate(
    [
      { opacity: 0, transform: "translateY(8px)" },
      { opacity: 1, transform: "translateY(0)" }
    ],
    { duration, easing: "ease-out", fill: "both" }
  )
  await anim.finished
}

async function closeDetail() {
  const duration = prefersReduced ? 1 : 180
  const anim = detail.animate(
    [
      { opacity: 1, transform: "translateY(0)" },
      { opacity: 0, transform: "translateY(-6px)" }
    ],
    { duration, easing: "ease-in", fill: "both" }
  )
  await anim.finished
  detail.hidden = true
}

toggle.addEventListener("click", async () => {
  if (isAnimating) return
  isAnimating = true

  const expanded = toggle.getAttribute("aria-expanded") === "true"
  if (expanded) {
    await closeDetail()
    toggle.setAttribute("aria-expanded", "false")
    toggle.textContent = "詳細を表示"
  } else {
    await openDetail()
    toggle.setAttribute("aria-expanded", "true")
    toggle.textContent = "詳細を閉じる"
  }

  isAnimating = false
})

注意点

finished はキャンセル時に reject されるため、複雑な画面では try/catch で保護しておくと安全です。モーダル遷移や画面切り替えと同時に動くUIでは特に注意が必要です。

また、display: none 状態ではアニメーションできないため、hidden の切り替え順序を統一してください。開くときは先に表示、閉じるときは終了後に非表示が基本です。

まとめ

Web Animations API は、依存を増やさずにUIモーションを実装したい現場で有効です。中規模以下の演出なら十分な表現力があり、既存画面への段階導入もしやすいです。

まずは開閉UIから始め、連打対策と reduced motion 対応をセットで入れる運用が実務では安定します。

ポイント

  • 標準APIだけで実務レベルの開閉演出を作れる
  • hiddenfinished の扱いを揃えると壊れにくい
  • 連打対策と reduced motion 対応を最初に入れる

参考リンク

read next