web-animation-css-animations について
インターフェース開発者向けの CSS アニメーションガイドです。トランジション、キーフレーム、スクロールタイムラインの使い分けと、描画コストや視覚効果を減らす設定を説明します。
主な機能
- 01トランジションとキーフレームの選択
- 02スクロール・ビューポート連動の動き
- 03コンポジター向けアニメーションのパターン
- 04視覚効果を減らす設定への対応
- 05イージングと時間の指針
活用シーン
- 01ホバーやフォーカス状態のアニメーション
- 02スピナーや表示時の演出作成
- 03スクロール連動の進捗表示
- 04視覚効果を減らす設定への対応
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill web-animation-css-animationsインストール後、Claude Code で/web-animation-css-animationsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/core.mdkeyframes.mdtransitions.md詳細
CSS アニメーションパターン
クイックガイド: 状態の変化(ホバー、フォーカス、切り替えられた属性)にはトランジションを使います。ループする動き、自動再生する動き、または3段階以上の動きには
@keyframesを使います。スクロールやビューポートに連動する進行にはanimation-timelineを使います。アニメーションをtransformとopacityに限定すると、各フレームはコンポジタースレッドで処理されます。また、すべてのアニメーションにprefers-reduced-motionの分岐を用意します。
詳細なリソース:
- examples/core.md — トークンシステム、インタラクティブな状態、登場、スピナー、トースト、動きを抑える設定
- examples/transitions.md — 複数プロパティのトランジション、段階的な遅延、アコーディオン、色、リンク
- examples/keyframes.md — スクロール駆動のタイムライン、
@propertyによるグラデーション、タイプライター、段階的なアニメーション、clip-path のモーフィング - reference.md — イージングの一覧、プロパティのコスト表、時間の目安、ブラウザーのサポート状況
該当する方法
- 動きが状態の変化である場合 —
:hover、:focus-visible、データ属性、または切り替えられたクラスなど — ベースルールにtransitionを指定するだけで実現できます。examples/transitions.md を参照してください。 - 動きがループする、自動再生される、または2つを超える状態を経由する場合 —
@keyframesとanimationのショートハンドが必要です。examples/keyframes.md を参照してください。 - 動きがスクロール位置またはビューポートへの進入を追跡する場合 — 時間ではなく
animation-timeline: scroll()またはview()が駆動します。キーフレームでは0から1までの進行を記述します。examples/keyframes.md を参照してください。
<critical_requirements>
CSS アニメーションコードを書く前に
transform と opacity をアニメーションさせます。 どちらもコンポジットされるため、フレームはメインスレッド外で実行され、タブがビジー状態でも維持されます。一方、width、top、margin はフレームごとにレイアウトを再計算します。
すべてのアニメーションに prefers-reduced-motion の分岐を用意します。 この設定は動きを完全に無効にするものではなく、前庭系への安全設定です。通常は、短い時間の不透明度フェードで状態の変化をわかりやすく保ちながら対応できます。
登場時は ease-out、退出時は ease-in を使います。 要素は登場時に減速して所定の位置に収まり、退出時には加速して離れていきます。連続回転を除き、linear は機械的な印象になります。
will-change は必要なインタラクションの範囲内で指定します。 宣言がある間は、コンポジティングレイヤーが保持されます。無差別なセレクターを使うと、ページ上の各要素に対してレイヤーが同時に1つずつ保持されます。
</critical_requirements>
自動検出: @keyframes、transition-property、transition-duration、animation-timeline、 scroll-timeline、view-timeline、animation-range、animation-fill-mode、prefers-reduced-motion、 will-change、cubic-bezier、linear()、@property、steps()、transform-origin
対象:
- 疑似クラス、データ属性、または切り替えられたクラスによって駆動される状態変化の動き
- 自律的な動き — スピナー、パルス、きらめき、注意喚起
- スクロール連動やビューポート進入に伴う進行
- ページがすでに設定しているクラスまたは属性をトリガーとする登場・退出の動き
ここでは扱わないもの:
- 実行時の再生制御 — 一時停止、逆再生、シーク、または進行状況の読み取り。CSS 宣言からはハンドルを取得できません。ハンドルを取得するには Web Animations API を使います。
element.animate()を呼び出すか、CSS ですでに宣言されたアニメーションに対してelement.getAnimations()を使います。 - 中断後も速度が引き継がれる動き。たとえば、ジェスチャーの途中で拾い上げられるスプリングなど
- アニメーションする値がポインター位置そのものである、ポインター追跡型のドラッグ
- ナビゲーションまたはビューの切り替え中に、退出するビューと入ってくるビューを同時に合成すること
<decision_framework>
イージングの選択
Element entering -> ease-out (fast start, slow settle)
Element exiting -> ease-in (slow start, fast departure)
Symmetric motion -> ease-in-out
Continuous rotation -> linear
Playful, overshooting -> cubic-bezier with a control point past 1
Anything else -> ease-out
ブラウザーのデフォルトである ease は汎用的すぎるため、隣り合う2つのアニメーションに指定すると、無関係なもののように見えます。代わりに、カーブを明示して指定してください。
CSSで表現できること
- スクロールとビューポートの進行度 —
animation-timeline: scroll()またはview()を指定し、animation-rangeで進行度の開始点と終了点を決めます - 複数要素にまたがる順序付け —
--indexカスタムプロパティからanimation-delayを算出し、backwardsのフィルモードで遅延中もアニメーション前の状態を維持します - 実行時に算出される値 — カスタムプロパティに値を書き込みます。アニメーション自体は 宣言的なままで、各フレームでそのプロパティを読み取ります
- オーバーシュートと任意の曲線 — 0〜1の範囲を超える
cubic-bezier、または どのcubic-bezierでも表現できない曲線を点のリストで指定するlinear()
</decision_framework>
基本パターン
パターン 1:アニメーショントークンシステム
デュレーション、イージング、移動距離をカスタムプロパティとして一度定義することで、 コンポーネント間でモーションの一貫性を保ち、1か所で調整できます。
:root {
--duration-fast: 150ms;
--duration-normal: 250ms;
--ease-out: cubic-bezier(0, 0, 0.2, 1); /* enter */
--ease-in: cubic-bezier(0.4, 0, 1, 1); /* exit */
--ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275); /* overshoot */
--lift-md: -4px;
}
コード全文:examples/core.md
パターン 2:コンポジターのみで行うトランジション
トランジションするプロパティをそれぞれ指定し、移動とサイズ変更を transform で表現することで、
どのフレームでもレイアウトが発生しないようにします。
.card {
transition:
transform var(--duration-fast) var(--ease-out),
opacity var(--duration-fast) var(--ease-out);
}
.card:hover {
transform: translateY(var(--lift-md)) scale(1.02);
}
translate() は top/left を、scale() は width/height を置き換えます。また、
opacity をアニメーションさせる疑似要素を使うことで、アニメーションする box-shadow を置き換えられます。
コード全文:examples/core.md
パターン 3:Prefers-Reduced-Motion
2つの形式があります。プログレッシブエンハンスメントでは、静止状態をベースにして モーションを有効にするため、後から追加したアニメーションがチェックをすり抜けることはありません。
.element {
opacity: 1;
transform: translateY(0);
}
@media (prefers-reduced-motion: no-preference) {
.element {
animation: fade-slide-in var(--duration-normal) var(--ease-out);
}
}
グレースフルデグラデーションでは、デフォルトでアニメーションさせ、reduce の場合に上書きします。
動きをなくすのではなく、短いフェードにする場合に適した形式です。
@media (prefers-reduced-motion: reduce) {
.notification {
animation: fade-in calc(var(--notification-duration) * 0.5) var(--ease-out);
}
}
動きを減らすことは、アニメーションをなくすことではありません。一般に opacity は安全です。
置き換える対象は、空間的な移動、拡大縮小、回転です。
コード全文:examples/core.md
パターン 4:@keyframes
ループするモーション、マウント時に自動再生するモーション、または2つを超える状態を経由するモーションに使います。
@keyframes fade-slide-in {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.modal {
animation: fade-slide-in var(--modal-enter-duration) var(--ease-out) forwards;
}
forwards は実行後に最終状態を維持し、backwards は animation-delay 中に初期状態を表示します。
コード全文:examples/core.md および examples/keyframes.md
パターン 5:Will-Changeのスコープ指定
will-change は要素を独自のコンポジットレイヤーに昇格させます。GPUメモリの消費量は
要素の描画面積に比例します。これからアニメーションするルールに指定してください。
.card:hover {
will-change: transform;
}
コード全文:examples/core.md
パターン 6:スクロール駆動アニメーション
animation-timeline は経過時間ではなくスクロールの進行度に基づいてキーフレームを制御します。
スクロールリスナーも、フレームごとの JavaScript も必要ありません。
.progress-bar {
animation: grow-width linear;
animation-timeline: scroll();
}
@keyframes grow-width {
from {
transform: scaleX(0);
}
to {
transform: scaleX(1);
}
}
scroll() はスクロールコンテナーの位置を追跡し、view() はビューポート内を通過する要素自体を追跡します。
animation-range でその範囲を指定します。
ブラウザー対応状況: Chrome/Edge 115+、Safari 26+、Firefox はフラグが必要です。
コード全文:examples/keyframes.md
パターン 7:カスタムプロパティのアニメーションに使う@property
カスタムプロパティを登録すると型が付与され、補間可能になります。グラデーションの角度や カラーのストップは、登録して初めてアニメーションします。
@property --gradient-angle {
syntax: "<angle>";
initial-value: 0deg;
inherits: false;
}
@keyframes rotate-gradient {
to {
--gradient-angle: 360deg;
}
}
ブラウザー対応状況: Chrome/Edge 85+、Safari 16.4+、Firefox 128+。
コード全文:examples/keyframes.md
<red_flags>
注意点
実行時に問題が発生します:
transition: all— 後から追加されたものも含め、すべてのプロパティが対象になり、レイアウトを発生させるプロパティまで拾ってしまいます — トランジション対象のプロパティを明示してくださいwidth、height、top、left、margin、paddingのアニメーション — フレームごとにレイアウトを再実行するため、メインスレッドがビジーになるとすぐにフレーム落ちします —transformをアニメーションさせ、レイアウトは変化させないでくださいbox-shadowのアニメーション — フレームごとに要素とその影を再描画します — 影を持たせた疑似要素のopacityをアニメーションさせてください- 恒久的なセレクターや広範囲に適用されるセレクターへの
will-change— 該当する要素ごとにコンポジットレイヤーを保持します。モバイルでは、レイヤーが十分に増えると GPU メモリを使い果たし、タブがクラッシュします — インタラクションのルールにのみ指定してください prefers-reduced-motionの分岐がないアニメーション — OS で動きを抑える設定にしているユーザーにも、移動量の大きい動きが表示されます — 後からではなく、アニメーションを書くときに分岐を追加してくださいforwardsのない入場アニメーション — 最終フレームで要素がアニメーション前の状態に戻ります — フィルモードを追加してください
予想外の動作:
- 祖先要素に
transformを指定すると包含ブロックが作られるため、子孫のposition: fixed要素はビューポートではなく、その祖先要素を基準に配置されます will-changeはスタッキングコンテキストを作成し、兄弟要素とのz-indexの解決方法を変えますanimation-fill-mode: backwardsがない場合、遅延のあるアニメーションでは、最初のフレームではなく最終状態が遅延中に描画されますdisplay: noneはアニメーションできません —opacityとvisibilityを使うか、grid-template-rowsを0frから1frへアニメーションさせてください- SVG パスの描画では
stroke-dasharrayとstroke-dashoffsetをアニメーションさせます。transformを使うと、パスは描画されずに移動します scroll()タイムラインにはスクロール可能な祖先要素が必要です —overflow: hiddenの親要素では進行しません- アニメーションは印刷時には実行されないため、アニメーション前の状態でも紙面上で読める必要があります
- およそ 1 秒を超える時間は、意図的というよりも遅く感じられます