T-CREATOR

JavaScript Web Animations API:滑らかに動く UI を設計するための基本と実践

JavaScript Web Animations API:滑らかに動く UI を設計するための基本と実践

Web アプリケーションにおいて、滑らかで心地よいアニメーションは、ユーザー体験を大きく向上させる重要な要素です。従来、JavaScript でアニメーションを実装する場合、CSS アニメーションや jQuery、あるいは requestAnimationFrame を使った独自実装など、さまざまな方法が混在していました。

しかし、Web Animations API(WAAPI)の登場により、JavaScript からアニメーションを直接制御できる標準的な手段が提供されるようになりました。この API は CSS アニメーションのパフォーマンスと、JavaScript の柔軟な制御を兼ね備えた、まさに「いいとこ取り」の技術なのです。本記事では、Web Animations API の基本から実践的な使い方まで、初心者の方にもわかりやすく解説していきますね。

背景

Web アニメーション実装の歴史

Web 開発におけるアニメーション実装は、時代とともに進化してきました。初期の Web サイトでは GIF アニメーションや Flash が主流でしたが、HTML5 の普及とともに CSS3 アニメーションが登場し、宣言的にアニメーションを記述できるようになりました。

JavaScript によるアニメーション制御も、setIntervalsetTimeout から requestAnimationFrame へと進化し、よりスムーズな描画が可能になっています。しかし、CSS アニメーションは柔軟性に欠け、JavaScript による独自実装は複雑になりがちという課題がありました。

Web Animations API の誕生

こうした背景から、W3C は 2014 年頃から Web Animations API の標準化を進めてきました。この API は、CSS アニメーションと JavaScript アニメーションの良い部分を統合し、より強力で使いやすいアニメーション制御を実現することを目指しています。

現在では、主要なブラウザでサポートされており、モダンな Web 開発において重要な技術となっているのです。

以下の図は、従来のアニメーション手法と Web Animations API の関係性を示しています。

mermaidflowchart TB
  old1["setInterval/setTimeout"] --> waapi["Web Animations API"]
  old2["requestAnimationFrame"] --> waapi
  css["CSS Animations"] --> waapi
  jquery["jQuery.animate()"] -.-> waapi

  waapi --> benefit1["パフォーマンス<br/>(CSS並み)"]
  waapi --> benefit2["柔軟な制御<br/>(JavaScript)"]
  waapi --> benefit3["標準化された<br/>API"]

この図からわかるように、Web Animations API は従来の複数の手法を統合し、それぞれの利点を活かした設計になっています。

主要ブラウザのサポート状況

#ブラウザサポート開始バージョン備考
1Chrome36+フル対応
2Firefox48+フル対応
3Safari13.1+フル対応
4Edge79+Chromium 版以降
5Opera23+フル対応

現在では、ほとんどのモダンブラウザで利用できるため、実務での採用も十分に検討できる状況です。

課題

従来のアニメーション実装における問題点

Web アニメーションを実装する際、開発者はいくつかの課題に直面してきました。それぞれの手法には、明確な制限や欠点が存在していたのです。

CSS アニメーションの制約

CSS アニメーションは宣言的で記述しやすい反面、動的な制御が困難です。アニメーションの途中で速度を変更したり、一時停止・再開したりする操作は、JavaScript から CSS クラスを切り替える複雑な実装が必要になります。

また、アニメーションの進行状況を取得することも容易ではありません。これにより、複雑なインタラクションを実装する際に大きな制約となっていました。

JavaScript による独自実装の複雑さ

一方、requestAnimationFrame を使った JavaScript 実装は柔軟性が高いものの、タイミング制御やイージング関数の実装など、低レベルな処理を自分で書く必要があります。

これは開発コストの増加につながり、また実装によってパフォーマンスにばらつきが生じる原因にもなっていました。

以下の図は、従来のアニメーション実装における課題を整理したものです。

mermaidflowchart TB
  subgraph css_issues["CSS アニメーションの課題"]
    css1["動的制御が困難"]
    css2["進行状況の取得が難しい"]
    css3["複雑なタイミング制御<br/>に不向き"]
  end

  subgraph js_issues["JavaScript 実装の課題"]
    js1["低レベルな処理の<br/>実装が必要"]
    js2["パフォーマンス最適化<br/>が難しい"]
    js3["コード量が多く<br/>なりがち"]
  end

  css_issues --> need["統一的な<br/>API の必要性"]
  js_issues --> need

  need --> waapi_solution["Web Animations API<br/>による解決"]

この図が示すように、CSS と JavaScript それぞれの課題を解決する統一的な API が求められていたのです。

具体的な実装上の困難

開発現場では、以下のような具体的な問題に悩まされることが多くありました。

#課題CSS の場合JavaScript の場合
1アニメーション制御クラス操作が必要自前実装が複雑
2進行状況の取得ほぼ不可能計算処理が必要
3一時停止・再開実装が困難状態管理が複雑
4複数要素の同期タイミング調整困難コード量増加
5パフォーマンス良好実装次第

これらの課題を解決し、開発者がより簡単に高品質なアニメーションを実装できる環境が必要だったのです。

解決策

Web Animations API による統合的アプローチ

Web Animations API は、従来の課題を解決するために設計された強力な API です。CSS アニメーションのパフォーマンスを維持しながら、JavaScript による柔軟な制御を可能にしています。

この API の最大の特徴は、Element.animate() メソッドを使って、わずか数行のコードでアニメーションを実装・制御できる点です。CSS で定義していたアニメーションを、そのまま JavaScript オブジェクトとして記述できるため、学習コストも低く抑えられます。

基本的な API 構造

Web Animations API の中心となるのは、Element.animate() メソッドです。このメソッドは、アニメーション対象の要素に対して呼び出し、キーフレームとオプションを指定することでアニメーションを実行します。

返り値として Animation オブジェクトが返され、このオブジェクトを通じてアニメーションの再生・一時停止・逆再生などの制御が可能になるのです。

以下の図は、Web Animations API の基本的な構造を示しています。

mermaidflowchart LR
  element["DOM 要素"] --|animate()|--> animation["Animation オブジェクト"]

  keyframes["キーフレーム<br/>(配列)"] --> animate_method["element.animate()"]
  optionsNode["オプション<br/>(duration, easing等)"] --> animate_method

  animate_method --> animation

  animation --> control1["play()"]
  animation --> control2["pause()"]
  animation --> control3["reverse()"]
  animation --> control4["cancel()"]
  animation --> stateInfo["currentTime<br/>playState など"]

この図が示すように、API はシンプルで直感的な構造になっており、要素に対してメソッドを呼び出すだけでアニメーションを開始できます。

Web Animations API の主要機能

この API が提供する主要な機能を、以下の表にまとめました。

#機能説明メリット
1キーフレーム定義CSS 風のオブジェクト記法直感的で理解しやすい
2タイミング制御duration、delay、iterations 等細かい調整が可能
3イージングease、linear、cubic-bezier 等自然な動きを実現
4再生制御play、pause、reverse 等動的な制御が容易
5状態取得playState、currentTime 等進行状況の監視が簡単
6Promise 対応finished、ready プロパティ非同期処理との連携

これらの機能により、従来の課題が包括的に解決されているのです。

アニメーションのライフサイクル

Web Animations API で作成されたアニメーションには、明確なライフサイクルが存在します。このライフサイクルを理解することで、より効果的にアニメーションを制御できるようになりますね。

mermaidstateDiagram-v2
  [*] --> idle: アニメーション生成
  idle --> pending: play() 呼び出し
  pending --> running: 開始遅延後
  running --> paused: pause() 呼び出し
  paused --> running: play() 呼び出し
  running --> finished_state: 完了
  finished_state --> running: play() 呼び出し
  running --> idle: cancel() 呼び出し
  paused --> idle: cancel() 呼び出し
  finished_state --> [*]

この状態遷移図により、アニメーションがどのような状態を持ち、どのように遷移するかが理解できます。各状態で適切なメソッドを呼び出すことで、意図した動作を実現できるのです。

具体例

基本的なフェードインアニメーション

まずは、最もシンプルなフェードインアニメーションから始めましょう。要素を徐々に表示させる、基本中の基本となる実装です。

以下のコードは、HTML 要素を取得してフェードインアニメーションを適用します。

html<!-- HTML -->
<div id="fadeTarget" class="box">フェードイン</div>
javascript// 対象要素を取得
const element = document.getElementById('fadeTarget');

次に、animate() メソッドを使ってアニメーションを定義します。第一引数にキーフレーム、第二引数にオプションを指定する形式です。

javascript// フェードインアニメーションを実行
const animation = element.animate(
  // キーフレーム:開始状態と終了状態を配列で指定
  [
    { opacity: 0 }, // 開始:完全に透明
    { opacity: 1 }, // 終了:完全に不透明
  ],
  // オプション:アニメーションの詳細設定
  {
    duration: 1000, // 1秒間かけて実行
    easing: 'ease-out', // 終わりに向けて減速
    fill: 'forwards', // アニメーション終了後も最終状態を維持
  }
);

このコードでは、opacity プロパティを 0 から 1 へと変化させることで、フェードイン効果を実現しています。fill: 'forwards' を指定することで、アニメーション終了後も opacity: 1 の状態が維持されます。

スライドインアニメーション

次は、要素を左からスライドさせながらフェードインさせる、より複雑なアニメーションです。複数のプロパティを同時にアニメーションさせることで、よりリッチな表現が可能になります。

javascript// スライド+フェードインアニメーション
const slideAnimation = element.animate(
  [
    {
      transform: 'translateX(-100px)', // 左に100px オフセット
      opacity: 0, // 透明
    },
    {
      transform: 'translateX(0)', // 元の位置
      opacity: 1, // 不透明
    },
  ],
  {
    duration: 800, // 0.8秒
    easing: 'ease-in-out', // 開始と終了を滑らかに
    fill: 'both', // 開始前と終了後の両方で状態を維持
  }
);

transformopacity を組み合わせることで、より動的で魅力的なアニメーションを作成できました。easing: 'ease-in-out' により、開始時と終了時に加減速が加わり、自然な動きになっています。

アニメーションの制御

Web Animations API の真価は、アニメーションを動的に制御できる点にあります。ユーザーの操作に応じて、一時停止や逆再生などを簡単に実装できるのです。

javascript// アニメーションオブジェクトを保持
const controlledAnimation = element.animate(
  [
    { transform: 'rotate(0deg)' },
    { transform: 'rotate(360deg)' },
  ],
  {
    duration: 2000,
    iterations: Infinity, // 無限ループ
  }
);

このアニメーションオブジェクトに対して、さまざまな制御メソッドを呼び出すことができます。

javascript// 一時停止
controlledAnimation.pause();

// 再開
controlledAnimation.play();

// 逆再生
controlledAnimation.reverse();

// キャンセル(初期状態に戻す)
controlledAnimation.cancel();

// 再生速度の変更(2倍速)
controlledAnimation.playbackRate = 2;

これらのメソッドを使うことで、ボタンクリックなどのイベントに応じたインタラクティブなアニメーションを実装できます。従来の CSS アニメーションでは困難だった、細かい制御が可能になっているのです。

進行状況の取得と監視

アニメーションの現在の状態や進行状況を取得することも、Web Animations API では簡単です。これにより、他の処理と連携させたり、UI に進捗を表示したりできます。

javascript// 再生状態の取得
console.log(animation.playState);
// 'idle', 'pending', 'running', 'paused', 'finished' のいずれか

// 現在の再生時間(ミリ秒)
console.log(animation.currentTime);

// アニメーション全体の長さ
console.log(animation.effect.getTiming().duration);

さらに、Promise を使ってアニメーションの完了を待つこともできます。

javascript// アニメーション完了を待つ
animation.finished.then(() => {
  console.log('アニメーションが完了しました');
  // 次のアニメーションを開始するなど
});

// アニメーションの準備完了を待つ
animation.ready.then(() => {
  console.log('アニメーションの準備ができました');
  // 正確なタイミングで何かを実行
});

これにより、複数のアニメーションを順番に実行したり、アニメーション完了後に特定の処理を行ったりすることが容易になります。

複数要素の連続アニメーション

実際のアプリケーションでは、複数の要素を順番にアニメーションさせたいケースがよくあります。Promise を活用することで、エレガントに実装できるのです。

以下は、リストアイテムを順番にフェードインさせる例です。

javascript// 複数の要素を取得
const items = document.querySelectorAll('.list-item');

// 連続してアニメーションさせる関数
async function animateSequentially() {
  for (let i = 0; i < items.length; i++) {
    // 各アイテムにアニメーションを適用
    const animation = items[i].animate(
      [
        { opacity: 0, transform: 'translateY(20px)' },
        { opacity: 1, transform: 'translateY(0)' },
      ],
      {
        duration: 400,
        easing: 'ease-out',
        fill: 'forwards',
      }
    );

    // 完了を待ってから次へ
    await animation.finished;

    // 少し間を空ける
    await new Promise((resolve) =>
      setTimeout(resolve, 100)
    );
  }
}

// 実行
animateSequentially();

この実装により、リストアイテムが順番に現れる滑らかなアニメーションを実現できます。async​/​await を使うことで、コードの可読性も高く保たれていますね。

キーフレームの詳細な制御

Web Animations API では、2 つのキーフレームだけでなく、より細かいステップを定義することもできます。オフセットを指定することで、アニメーションの途中経過を詳細に制御できるのです。

javascript// 複雑なバウンスアニメーション
const bounceAnimation = element.animate(
  [
    // 各キーフレームにオフセット(0〜1の値)を指定可能
    { transform: 'translateY(0)', offset: 0 }, // 0%の時点
    { transform: 'translateY(-100px)', offset: 0.4 }, // 40%の時点
    { transform: 'translateY(-50px)', offset: 0.6 }, // 60%の時点
    { transform: 'translateY(-75px)', offset: 0.8 }, // 80%の時点
    { transform: 'translateY(0)', offset: 1 }, // 100%の時点
  ],
  {
    duration: 1500,
    easing: 'linear',
  }
);

この例では、バウンスするような動きを実現するために、5 つのキーフレームを定義しています。offset プロパティで各キーフレームのタイミングを指定することで、細かい動きの調整が可能です。

イージング関数のカスタマイズ

アニメーションの「緩急」を制御するイージング関数も、柔軟にカスタマイズできます。CSS と同じく、cubic-bezier を使った独自のイージング曲線を定義できるのです。

javascript// カスタムイージングを使ったアニメーション
const customAnimation = element.animate(
  [{ transform: 'scale(1)' }, { transform: 'scale(1.5)' }],
  {
    duration: 1000,
    // ベジェ曲線でカスタムイージング
    easing: 'cubic-bezier(0.68, -0.55, 0.265, 1.55)',
    fill: 'forwards',
  }
);

この cubic-bezier(0.68, -0.55, 0.265, 1.55) は、オーバーシュート(行き過ぎてから戻る)効果を持つイージング曲線です。こうしたカスタマイズにより、ブランドやデザインに合わせた独自の動きを作り出せます。

実践的なユースケース:モーダルの表示

実際のアプリケーションでよく使われる、モーダルダイアログの表示アニメーションを実装してみましょう。背景のオーバーレイとモーダル本体を、それぞれアニメーションさせます。

javascript// モーダル表示関数
function showModal() {
  const overlay = document.getElementById('overlay');
  const modal = document.getElementById('modal');

  // 要素を表示
  overlay.style.display = 'block';
  modal.style.display = 'block';

  // オーバーレイのフェードイン
  overlay.animate([{ opacity: 0 }, { opacity: 1 }], {
    duration: 300,
    easing: 'ease-out',
    fill: 'forwards',
  });

  // モーダルのスケール+フェードイン
  modal.animate(
    [
      {
        transform: 'scale(0.7)',
        opacity: 0,
      },
      {
        transform: 'scale(1)',
        opacity: 1,
      },
    ],
    {
      duration: 300,
      easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
      fill: 'forwards',
    }
  );
}

この実装では、オーバーレイとモーダルを別々にアニメーションさせることで、より洗練された表示効果を実現しています。

モーダルを閉じる際も、同様にアニメーションを適用できます。

javascript// モーダル非表示関数
async function hideModal() {
  const overlay = document.getElementById('overlay');
  const modal = document.getElementById('modal');

  // モーダルのアニメーション
  const modalAnim = modal.animate(
    [
      {
        transform: 'scale(1)',
        opacity: 1,
      },
      {
        transform: 'scale(0.7)',
        opacity: 0,
      },
    ],
    {
      duration: 200,
      easing: 'ease-in',
      fill: 'forwards',
    }
  );

  // オーバーレイのアニメーション
  const overlayAnim = overlay.animate(
    [{ opacity: 1 }, { opacity: 0 }],
    {
      duration: 200,
      easing: 'ease-in',
      fill: 'forwards',
    }
  );

  // 両方のアニメーション完了を待つ
  await Promise.all([
    modalAnim.finished,
    overlayAnim.finished,
  ]);

  // アニメーション完了後に要素を非表示
  overlay.style.display = 'none';
  modal.style.display = 'none';
}

Promise.all() を使うことで、複数のアニメーションが完了するのを効率的に待つことができます。完了後に display: none を設定することで、DOM から完全に隠すことができるのです。

パフォーマンス最適化のポイント

Web Animations API は高パフォーマンスですが、さらに最適化するためのポイントがいくつかあります。特に、アニメーション対象のプロパティ選択が重要です。

以下の表は、アニメーション可能なプロパティとそのパフォーマンスへの影響をまとめたものです。

#プロパティ種別パフォーマンス理由
1transformtranslate, scale, rotate★★★GPU で処理される
2opacityopacity★★★GPU で処理される
3colorcolor, background-color★★☆CPU 処理だが軽量
4layoutwidth, height, margin★☆☆レイアウト再計算が発生
5paintborder, box-shadow★☆☆再描画が必要

可能な限り transformopacity を使うことで、最高のパフォーマンスを得られます。

javascript// 推奨:transform を使った実装
element.animate(
  [
    { transform: 'translateX(0)' },
    { transform: 'translateX(100px)' },
  ],
  { duration: 500 }
);

// 非推奨:left を使った実装(レイアウト再計算が発生)
element.animate([{ left: '0px' }, { left: '100px' }], {
  duration: 500,
});

同じ視覚効果でも、transform を使うことで GPU アクセラレーションが効き、スムーズなアニメーションになります。

まとめ

Web Animations API は、モダンな Web アプリケーションにおいて、滑らかで制御可能なアニメーションを実装するための強力なツールです。CSS アニメーションのパフォーマンスと、JavaScript の柔軟な制御を両立させた、まさに理想的な API といえるでしょう。

本記事では、Web Animations API の基本から実践的な使い方まで解説してきました。Element.animate() メソッドを使った基本的なアニメーションから、Promise を活用した複数要素の制御、実際のアプリケーションで使えるモーダル表示まで、幅広くカバーしています。

重要なポイントをまとめると、以下のようになります。

  • シンプルな API: animate() メソッド一つで直感的にアニメーションを実装できる
  • 柔軟な制御: play、pause、reverse など、動的な制御が簡単
  • Promise 対応: 非同期処理との連携や、アニメーションの順次実行が容易
  • 高パフォーマンス: 特に transform と opacity は GPU アクセラレーションが効く
  • 標準化: 主要ブラウザでサポートされ、実務でも十分に使える

この API をマスターすることで、ユーザー体験を大きく向上させる、魅力的な UI を構築できるようになります。ぜひ実際のプロジェクトで活用して、滑らかで心地よいアニメーションを実装してみてください。

最初は基本的なフェードインやスライドから始めて、徐々に複雑なアニメーションに挑戦していくことをおすすめします。Web Animations API は学習曲線が緩やかで、段階的にスキルアップできる技術なのです。

関連リンク