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 かだけで描画性能は決まりません。
4. SVG なら必ず軽いとは限らない
転送サイズと再生中の描画コストは別に考えます。単純な図形は簡潔ですが、複雑なパス、フィルター、多数の DOM 要素は処理を増やします。SVG が常に GIF より小さく、全端末で一定の FPS を出すとは限りません。
ブラウザーは必要なスタイル計算、レイアウト、ペイント、合成で画面を更新します。動かす属性、描画領域、同時再生数が重要です。transform と opacity を優先的に検討し、対象の SVG とブラウザーで実際の合成処理を確認してください。
| 効果 | 主な属性 | 確認するコスト |
|---|---|---|
| 回転・移動・拡縮・フェード | transform, opacity | 合成が有効な場合がありますが、GPU 実行やペイント省略を常に保証するものではありません。 |
| 線描画・図形の変化 | stroke-dashoffset, d | 再描画を確認します。複雑なパスを多数動かすと負荷が増えます。 |
| ぼかし・影・多数の図形 | filter、図形数と描画領域 | フィルターの範囲や図形数を減らし、ペイント時間とメモリーを比較します。 |
5. 実際の画面に組み込む前に
- 成功やエラーの短いフィードバックは必要なときに再生し、無限ループの目的を確認します。
- 長いリストでは IntersectionObserver で画面外のループを止め、非表示タブも確認します。Motive の一覧は画面内のカードだけ再生します。
- prefers-reduced-motion: reduce を尊重し、静止状態でも意味が伝わるようにします。装飾には aria-hidden、情報を伝える画像には適切な代替テキストを使います。
- width と height で表示領域を確保します。インライン SVG を繰り返す場合、タイトル、マスク、グラデーションの ID が重複しないようにします。
- すべてのアイコンに will-change を先に指定せず、問題を測定してから必要な要素だけに適用し、効果を比較します。
6. 同じ条件で性能を測定する
- アイコン、サイズ、動き、時間を固定します。同時再生数を 1、20、100 と変え、表示中の数と全体数を記録します。
- 本番に近いビルドを使い、Network で圧縮後の転送量とリクエスト数を確認します。ファイルサイズだけで再生性能を判断しません。
- DevTools の Performance で再生とスクロールを記録し、Layout、Paint、フレーム遅延を比較します。60Hz の 1 フレームは約 16.7ms ですが、ページ全体の処理の予算です。測定なしに FPS を保証しません。
- 実際のモバイル端末で、動きを減らす設定、画面外、非表示タブ、有限の繰り返しも確認します。端末、ブラウザー、条件を記録して再現できるようにします。