← アイコン一覧へ戻る

MOTIVE · 記事

SVG アニメーションの仕組みと、軽く動かすための考え方

通知を有効にすると揺れるベル、処理が終わると描かれるチェック。小さな動きが状態の変化を伝えます。SVG が動きを作る仕組みと、多数のアイコンを使う際の確認点を見ていきます。

1. 図形に時間の変化を加える

SVG は path、circle、rect などの図形を座標と属性で表します。viewBox="0 0 24 24" は内部座標系を、width と height は表示サイズを定義します。同じ図形を異なる大きさで使えます。

アニメーションは時間とともに属性を変えることです。最初の回転角を 0 度、途中を -18 度、最後を 0 度にするとベルが揺れます。ブラウザーは duration と easing に従ってキーフレームの間を補間するため、各フレームの画像を保存する必要はありません。

2. 破線の開始位置でチェックを描く

チェックの図形は最初から存在しています。stroke-dasharray で線と空白のパターンを作り、stroke-dashoffset で開始位置を動かすと線が徐々に現れます。

例では pathLength="60" で距離計算の基準をそろえ、dashoffset を 60 から 0 に変えます。60 は画面上のピクセル数ではありません。基本属性は完成したチェックなので、アニメーションを無効にしても意味が残ります。コードを HTML に貼り付けて試せます。

MDN · stroke-dashoffsetMDN · pathLength

線を描く動作例

同じ SVG と CSS を下に掲載しています。停止・再開でき、動きを減らす設定では完成したチェックを表示します。

<svg xmlns="http://www.w3.org/2000/svg"
     width="64" height="64" viewBox="0 0 24 24"
     fill="none" stroke="currentColor" stroke-width="2"
     stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
  <style>
    .motive-draw { animation: motive-draw 1.8s ease-in-out infinite; }
    @keyframes motive-draw {
      0% { stroke-dashoffset: 60; }
      60%, 100% { stroke-dashoffset: 0; }
    }
    @media (prefers-reduced-motion: reduce) {
      .motive-draw { animation: none; }
    }
  </style>
  <path class="motive-draw" d="m6 12 4 4 8-8"
        pathLength="60" stroke-dasharray="60" stroke-dashoffset="0" />
</svg>

3. CSS と Web Animations API の役割

決まった動きを繰り返す、または一度再生する場合は CSS @keyframes が適しています。Motive の SVG は CSS を含み、追加のアニメーションライブラリーを必要としません。img 内の SVG の内部要素はページから直接選択できません。図形ごとの操作にはインライン SVG を検討してください。

再生・停止・シークを扱うエディターでは Web Animations API が便利です。Motive は同じモーションモデルからプレビューのキーフレームと出力 CSS を生成します。毎フレーム React の状態を更新する方式ではありません。CSS か JavaScript かだけで描画性能は決まりません。

MDN · Web Animations API

4. SVG なら必ず軽いとは限らない

転送サイズと再生中の描画コストは別に考えます。単純な図形は簡潔ですが、複雑なパス、フィルター、多数の DOM 要素は処理を増やします。SVG が常に GIF より小さく、全端末で一定の FPS を出すとは限りません。

ブラウザーは必要なスタイル計算、レイアウト、ペイント、合成で画面を更新します。動かす属性、描画領域、同時再生数が重要です。transform と opacity を優先的に検討し、対象の SVG とブラウザーで実際の合成処理を確認してください。

4. SVG なら必ず軽いとは限らない
効果主な属性確認するコスト
回転・移動・拡縮・フェードtransform, opacity合成が有効な場合がありますが、GPU 実行やペイント省略を常に保証するものではありません。
線描画・図形の変化stroke-dashoffset, d再描画を確認します。複雑なパスを多数動かすと負荷が増えます。
ぼかし・影・多数の図形filter、図形数と描画領域フィルターの範囲や図形数を減らし、ペイント時間とメモリーを比較します。

web.dev · High-performance CSS animations

5. 実際の画面に組み込む前に

  • 成功やエラーの短いフィードバックは必要なときに再生し、無限ループの目的を確認します。
  • 長いリストでは IntersectionObserver で画面外のループを止め、非表示タブも確認します。Motive の一覧は画面内のカードだけ再生します。
  • prefers-reduced-motion: reduce を尊重し、静止状態でも意味が伝わるようにします。装飾には aria-hidden、情報を伝える画像には適切な代替テキストを使います。
  • width と height で表示領域を確保します。インライン SVG を繰り返す場合、タイトル、マスク、グラデーションの ID が重複しないようにします。
  • すべてのアイコンに will-change を先に指定せず、問題を測定してから必要な要素だけに適用し、効果を比較します。

MDN · prefers-reduced-motion

6. 同じ条件で性能を測定する

  1. アイコン、サイズ、動き、時間を固定します。同時再生数を 1、20、100 と変え、表示中の数と全体数を記録します。
  2. 本番に近いビルドを使い、Network で圧縮後の転送量とリクエスト数を確認します。ファイルサイズだけで再生性能を判断しません。
  3. DevTools の Performance で再生とスクロールを記録し、Layout、Paint、フレーム遅延を比較します。60Hz の 1 フレームは約 16.7ms ですが、ページ全体の処理の予算です。測定なしに FPS を保証しません。
  4. 実際のモバイル端末で、動きを減らす設定、画面外、非表示タブ、有限の繰り返しも確認します。端末、ブラウザー、条件を記録して再現できるようにします。

公式の参考資料