Communitygithub.com

igal-commits/animating-web-pages

Webページにモーション(スクロールリビール、ヒーローイントロ、クロスフェード、アンビエントループ、ループ背景動画、画像ローテーター、スティッキー要素など)を追加または修正する場合、またはアニメーションがカクつく、タイミングが合わない、画面外で再生される、まったく動作しない場合に使用します。

animating-web-pages とは?

このスキルは、Webページのアニメーションに関する問題を診断・修正するための実践的なガイドです。アニメーションが「まったく動作しない」場合と「動作はするがパフォーマンスが悪い」場合の両方のケースをカバーし、具体的な原因と解決策を提供します。セレクタの一致確認、交差監視の設定、スクロールトリガーのリフレッシュなど、デバッグの体系的なアプローチを説明します。また、スクロールリビール、ヒーローイントロ、クロスフェード、アンビエントループ、ループ背景動画、画像ローテーター、スティッキー要素などのモーションを追加するためのベストプラクティスを網羅します。さらに、アニメーションの吃音(スタッター)を診断し、低フレームレートの移動やダブルスムージングなどの原因を特定して修正する方法を提供します。必須のフォールバックとして、動きの抑制設定、スクリプトなしの状態、モバイル対応をカバーし、各アニメーションが宣言どおりに動作していることを確認するための検証チェックリストを含みます。このスキルは、GSAPやScrollTriggerなどのライブラリと連携するように設計されており、あらゆるWebアニメーションプロジェクトに実用的なリファレンスを提供します。

対応~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/igal-commits/landing-page-skills/tree/HEAD/skills/animating-web-pages

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

Webページのアニメーション

概要

Webのモーションは、2つの方法で失敗します。動作しないか、動作が悪いかです。どちらにも、特定可能な原因があります。イージングカーブを推測することは、最初に行うことではなく、最後に行うことです。

基本原則:アニメーションを調整する前に、それが意図した要素で実行されていることを証明すること。

固定された、スクラブされるシーンのデザインについては、choreographing-scroll-storiesを参照してください。このスキルは、モーションを実行させ、適切に動作させるためのメカニズムです。

アニメーションがまったく動作しない場合

以下の順序で確認してください。最初の3つでほとんどすべての原因が明らかになります。

症状原因確認方法
何も動かない、要素は表示されているセレクタが一致する要素がゼロコンソールで document.querySelectorAll(sel).length
何も動かない、要素は非表示リビールに opacity: 0 が設定され、トリガーが発火しなかった要素の computed opacity
クロスフェードが機能しない両方のレイヤーが opacity: 1 で、"on" のルールのみ存在する入ってくるレイヤーを 0 に設定する休止状態のルールが存在する必要がある
読み込み直後に発火するトリガーがレイアウト確定前に評価された画像がページのサイズを決定する load の後に実行する。DOMContentLoaded ではない
一度発火した後に二度と発火しないonce: true と、再エントリーする要素意図的か?
非表示タブやヘッドレスパネルで動作しないdocument.hidden の間、ティッカーが一時停止している強制する:gsap.ticker.lagSmoothing(0); gsap.ticker.tick()
トリガーが数百ピクセルずれているトリガーが測定された後に画像が読み込まれた読み込み時とリサイズ時に ScrollTrigger.refresh()(200msのデバウンス)

クロスフェードの症状は、コードレビューでは正しく見えるため、詳しく説明する価値があります:

/* これだけでは何も起こらない。 */
.tile.is-swapped .layer.is-alt { opacity: 1 }

/* 休止状態がアニメーションを成立させる。 */
.layer.is-alt { opacity: 0 }
.tile.is-swapped .layer.is-alt { opacity: 1 }

イントロとアンビエントモーション

  • 見出しはすぐに表示されること。 イントロは、見出しが約1.1秒で表示されるようにカットすること。3.8秒のイントロはローディング画面です。
  • 写真は、1つのセルから別のセルにフェードアウトして変化すること。スライドしないこと。 各写真は1つの要素であり、画面に2度表示されることはなく、そのコピーがフェードインしている間にフェードアウトすることもありません。
  • アンビエントの変化は遅く、不規則であること。 1.8秒から3.4秒ごとに1つのタイルが変化する場合、各タイルの変化は遅く、生きているグリッドとして読み取られます。各タイルをより速く変化させるために間隔を短くしないでください。
  • ラウンドごとにシャッフルすること。 すべてのタイルが繰り返される前に一度ずつ変化し、各選択は最後の3つのうちの遠い半分から行われます。
  • 誰も見えないものは一時停止すること。 アンビエントループは画面外と非表示タブで停止し、中断した場所から再開します。
  • 戻るたびにイントロが再生されないこと。 イントロが安定した後は、アンビエントレイヤー以外は動きません。

スクロールリビール

  • 読み込み時に実際にフォールドの下にある要素にのみ opacity: 0 を設定すること。すべてを全面的に非表示にすると、フォールドより上の要素は、発生しないかもしれないスクロールまで見えなくなります。
  • 完全な交差ではなく、top 88% でリビールすること。要素が完全にビュー内に入るのを待つと、読者がすでにそれを見ているときにアニメーションが実行されます。
  • コンポーネント内ではなく、兄弟間でスタガーを設定すること。カード間は60-90ms、カード内は0。
  • 要素ごとに1つではなく、グループごとに1つのオブザーバーでバッチ処理すること。

動画

自動再生の背景動画には、普遍的なバグが1つあります。動画が画面外で再生され、オブザーバーがそれを一時停止し、読者が到着する頃にはループが15秒進んでいて、冒頭のビートが失われています。

autoplay属性を完全に削除します。
初期化時に pause() と load() を実行します。
最初の交差時のみ:currentTime = 0、次に play() を実行します。

992px未満またはデバイスピクセル比1.5未満では1xファイルを提供し、動画がデコードされる前のペイント用にポスターフレームを提供します。負荷の高いホームページ動画は帯域幅を消費する場所でもあるため、監査してください。

スタッター(吃音)

静止写真でのゆっくりとしたドリフトが最も一般的な原因です。1フレームあたり約1ピクセル未満のケンバーンズ効果は、フレームごとに画像をリサンプリングし、揺らぎとして認識され、モーションとしては認識されません。

  • モーションとして認識できるほど十分に動かすか、まったく動かさないかのどちらかです。
  • レンダリングされた動画内の静止フレームについては、同一フレームを再エンコードするのではなく、エンコードされたフレームをバイト単位でコピーします。それ以外の方法ではドリフトが発生します。
  • ループの継ぎ目を確認します。フレーム0と最終フレームが異なる場合、ループはサイクルごとに目に見えてジャンプします。それらの間の平均絶対差を測定します。
  • ダブルスムージングを行わないでください。スムーススクロールライブラリと重い scrub 値が組み合わさると、ホイールに遅れるページが発生します。スムーススクロールライブラリが存在する場合は、scrub: 0.2 を使用します。

スティッキー

CSSグリッド内の position: sticky は、コンテナ全体ではなく、グリッド領域 に対して解決されます。自身のコンテンツの高さしかないスティッキーアイテムは移動スペースがなく、すぐに解放されます。

.grid  { align-items: stretch }      /* 領域がフルハイトになる */
.col   { position: static; height: 100% }
.inner { position: sticky; top: 10rem }

フォールバック

すべてのアニメーションには、モーション仕様書に記載され、テストされた3つのフォールバックがあります。

  • 動きの抑制(Reduced motion)。 prefers-reduced-motion: reduce と ?static クエリは、積み重ねられた、完了した状態をレンダリングします。固定されたものはなく、非表示のものもなく、すべてのシーンは最終状態にあります。追加したすべてのCSS transition もカバーします。アニメーション化されたセレクタをリストしても、コンテナのトランジションを忘れると、色がまだスライドしている状態になります。
  • スクリプトなし(No script)。 すべての要素が表示されたままになります。スクリプトが開始されなかった場合、約3.5秒後にクラスが追加され、CSSはその下のすべてをリビールします。
  • 携帯電話(Phones)。 固定されたシーンは積み重なります。それを明記し、テストします。

検証

コードからアニメーションが動作していると報告しないでください。ページ上で確認します:

  • アニメーション化されたすべてのグループのセレクタ数がゼロ以外である
  • フォールドより上の要素の computed opacity が、スクロール前に1である
  • 動画の currentTime が、最初に表示された瞬間に0.5秒未満である
  • 動きの抑制エミュレーションにより、ページが完全に読み取り可能で静的になる
  • スクリプトなしですべてが表示されたままになる
  • width、height、top、left をアニメーション化しない。transform と opacity を使用する
  • アンビエントループは、画面外ではスタイル変更を行わない

危険信号(Red flags)

  • セレクタの一致を確認する前に、期間やイージングを調整する
  • 対応する休止状態のルールがない .is-active ルール
  • transition: all
  • セクションが「空っぽに感じられた」ために追加されたアニメーション
  • スライドする写真
  • 同じ写真が画面に2度表示される

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル