目次
情報確認日:2026年10月15日。GSAP 3系の公式資料を確認して作成した、本サイト独自の実装例です。
CSSの配置変更をFlipでつなぐ方法を説明します。getState、DOM変更、fromの順序と、連打・フォーカス・フレームワークでの注意点を扱います。
スポンサーリンク
レイアウトの正解はCSSとDOMに持たせる
カードの順番や大きさが変わるとき、変更前後の座標をすべて自分で計算するのは手間がかかります。Flipは変更前の状態を記録し、変更後の状態との差をアニメーションへ使うためのプラグインです。最終的な配置はCSSとDOMで作り、その間の見た目をつなぎます。
今回のサンプルは、四つのカードのDOM順を反転します。CSSのorderで見た目だけを逆にするのではなく、文書の順序も変えます。業務上の順位を保存するデータ処理は含めていません。サーバーへ並び順を保存する場合は、画面の演出とは別に更新結果と失敗時の扱いを設計します。
最重要なのはgetStateを呼ぶタイミング
順番は、まずFlip.getState(items)、次にDOMやクラスの変更、最後にFlip.from(state, options)です。状態を取る前にDOMを変更してしまうと、変更前の配置を失います。Flip.fromへ古い状態を繰り返し渡すのではなく、一回の変更に対応する状態を取得してください。
getStateは、対象要素の位置やサイズなどを記録します。アプリケーションのデータ全体をコピーする関数ではありません。カードの内容、保存先の順位、選択中のIDなどは、通常のアプリケーションの状態として管理します。
スポンサーリンク
最終位置へ変更してからアニメーションを作る
grid.append(item)は既存の要素を移動する処理であり、カードを複製する処理ではありません。全要素を逆順に追加し直した時点で、ブラウザー上のDOMは新しい順番です。その状態と記録済みの配置の差をFlip.fromが使います。
見た目の移動が終わるまでDOM変更を待つのではありません。これにより、動きを減らす設定ならFlip.fromを呼ばず、そのまま最終状態を表示できます。「アニメーションを実行しないと正しい順序にならない」という依存を作らないことが重要です。
absoluteを無条件に加えない
Flipの例にはabsolute: trueが使われることがありますが、すべての並べ替えに必須ではありません。一時的な絶対配置はレイアウトの占有領域へ影響するため、親の高さや周囲の要素も確認する必要があります。この例は同じ大きさのカードをGrid内で移すので、まず基本の構成にしています。
異なる大きさのカード、消える要素、新しく入る要素を扱う場合は、対象範囲と親要素を含めて検討します。どこが高さを確保するのかを説明できない状態で、オプションだけ足して重なりを隠さないでください。
スポンサーリンク
連打された場合のルールを決める
サンプルは、前のFlipが残っていたらprogress(1)で完了位置へ進め、それから次の状態を取得します。途中の動きを滑らかに引き継ぐことより、短いデモとして状態が追いやすいことを優先しています。連打時に小さな飛びが見える可能性があることも、実機で確認してください。
本番では、処理中はボタンを無効にする、最後の要求だけを受ける、途中の状態から再計算するなどの選択肢があります。どれがよいかは、並べ替えが単なる表示変更なのか、サーバー更新を伴う操作なのかで違います。アニメーションの完了を、保存完了と同じ意味で表示しないようにします。
フォーカスと読み上げにも順序の変更を伝える
今回のカードはフォーカスを持たない説明要素です。カード内へ入力欄やリンクを追加して移動すると、ブラウザーによってフォーカスの扱いを確認する必要があります。必要なら変更前のactiveElementを記録し、適切な対象へ戻す設計を検討します。
role="status"の文章で現在の順序を知らせています。移動する見た目だけに頼らず、何が変わったか分かるようにするためです。ただし、大量のカード名を毎回読み上げると負担になるので、実際の件数では通知の長さを調整してください。
ReactやVueでは描画完了を待つ
素のDOM操作と違い、フレームワークの状態更新が、その行の直後にDOMへ反映されるとは限りません。状態取得、データ更新、描画完了後のFlip.fromという順序を保つ必要があります。VueならnextTickなど、その環境に合った完了点を使います。
確認するのは、初回の一回だけでなく、連打、画面幅変更、項目数の増減、reduce設定です。最終的なDOM順と見た目が一致するかを先に点検し、その後でdurationやstaggerを調整すると、見た目の問題とデータの問題を混同しにくくなります。
実装例:HTML・CSS・JavaScript
以下は独立したデモ用のコードです。既存のViteなど、npmパッケージを解決できる開発環境で npm install gsap を実行し、HTMLをbody内、CSSをスタイルシート、JavaScriptをmain.jsへ配置してください。main.jsはHTMLの末尾からtype="module"で読み込みます。WordPressの記事本文へそのまま実行用スクリプトを貼る例ではありません。
<button id="sort" type="button">並びを反転</button>
<p id="sort-status" role="status">初期の順序です。</p>
<ul class="grid">
<li class="item">企画</li><li class="item">設計</li>
<li class="item">実装</li><li class="item">検証</li>
</ul>
.grid { display:grid; grid-template-columns:repeat(2,minmax(0,1fr));
list-style:none; padding:0; max-width:36rem; gap:1rem; margin:2rem auto; }
.item { padding:3rem 1rem; text-align:center; background:#00bae2; border-radius:1rem; }
.item:nth-child(even) { background:#fec5fb; }
import { gsap } from "gsap";
import { Flip } from "gsap/Flip";
gsap.registerPlugin(Flip);
const grid = document.querySelector(".grid");
const button = document.querySelector("#sort");
let running;
button.addEventListener("click", () => {
running?.progress(1);
const items = [...grid.children];
const state = Flip.getState(items);
items.reverse().forEach((item) => grid.append(item));
document.querySelector("#sort-status").textContent =
"現在の順序:" + [...grid.children].map((el) => el.textContent).join("、");
if (matchMedia("(prefers-reduced-motion: reduce)").matches) return;
running = Flip.from(state, { duration: 0.65, ease: "power2.inOut", stagger: 0.04 });
});
スポンサーリンク
サンプルを確認するときの条件
APIの使い方は公式資料と照合しています。掲載コードはGSAP 3.15.0とDOMを模した環境で読み込み・操作を確認しましたが、実ブラウザーでの見た目、タッチ操作、描画性能を保証するものではありません。採用前に対象ブラウザーと実機で確認してください。JavaScriptを無効にした状態でも、必要な内容と操作が残るかを確認します。



![JavaScriptモダンプログラミング完全ガイド [堅牢なコードを効率的に開発できる! ]](https://m.media-amazon.com/images/I/91NvEBSfCkL._SL1500_.jpg)