速報

X.Orgのクライアントライブラリーで17件を修正!Linux端末と画像処理の利用範囲を点検

CATEGORY

【GSAP】context・revert・quickToでアニメーションの後片付けと性能を改善する

※本ページのリンクにはプロモーションが含まれています。

濃い背景に配置したGSAP公式ブランドロゴ

目次

情報確認日:2026年10月15日。GSAP 3系の公式資料を確認して作成した、本サイト独自の実装例です。

ページ遷移で増え続けるアニメーションを防ぎ、ポインター追従をquickToで実装します。Tweenの寿命、イベントの解除、座標系、計測してから最適化する手順を整理します。

スポンサーリンク

一度動くことより、繰り返し開いても増えないこと

初回の画面では滑らかでも、SPAの遷移やモーダルの開閉を繰り返すと処理が増える場合があります。GSAPのTweenだけでなく、イベント、タイマー、Observer、独自の参照などが残っている可能性があります。性能の改善は、まず不要な処理を終了させられることから始めます。

サンプルは、装飾の丸がポインターへ追従する小さな画面です。「初期化し直す」を何度押しても、前の処理を片付けてから新しい処理を作ります。「停止して片付ける」でイベントも解除します。通常のカーソルや文章の操作を置き換えるものではありません。

contextは生成を記録する境界

gsap.context()は、その中で作成したGSAPのアニメーションなどをまとめて元へ戻すために使えます。対象の部品をスコープにできるため、同じクラスがページ内の別の場所にあっても、意図せず操作しにくくなります。

Contextは、Timelineのように再生順を組み立てる道具ではありません。何をどのタイミングで片付けるかをまとめる境界です。サンプルでは条件に応じた生成も必要なため、Contextの管理を内包するmatchMediaを使用しています。条件変更時と手動停止の両方へ、同じ片付けの考え方を適用します。

スポンサーリンク

killとrevertの目的を使い分ける

kill()はアニメーションを止めるために使いますが、加えたスタイルをすべて初期状態へ戻すこととは同じではありません。要素を別のレイアウトで使い直す場合などは、残ったインラインスタイルがCSSを上書きしていないか確認します。

revert()は、アニメーションが加えた状態を元へ戻す用途で使います。gsap.context()ならctx.revert()、matchMediaならmm.revert()で、その管理範囲を片付けます。ただし、画面のDOM自体を削除する処理や、任意の業務データを元へ戻す処理まで自動で行うわけではありません。

後から呼ばれるコールバックに注意する

クリックやsetTimeoutの中で新しいgsap.toを作る場合、その実行が初期化時のContextに記録されるかを確認します。外側の関数がContext内で一度登録されたからといって、後日のすべての生成が自動で同じ記録へ入るとは限りません。Contextのaddで記録する設計などが必要になる場合があります。

この例はイベント内で毎回Tweenを新規生成せず、最初に作ったquickToの関数へ数値を渡します。返したクリーンアップ関数でpointermoveのイベントも外します。GSAPの管理範囲と、ブラウザーのイベント管理範囲を分けて説明できる状態にしておきます。

スポンサーリンク

quickToは同じ数値プロパティを繰り返し更新する用途

ポインターの移動ごとに新しいTweenを作る代わりに、x用とy用のquickToを一度生成します。新しい目標値を渡すと、再利用するTweenの向きをその値へ変えられます。多数の小さな処理を毎回作る構成を避けたい場合に候補になります。

通常のgsap.toと同じ便利機能をすべて受け取る関数ではありません。この例はxとyへ数値だけを渡します。相対値、任意のプラグイン設定、複雑な単位変換を同じ感覚で渡すのではなく、quickToが対応する用途に限定してください。

座標系を揃えて、無駄な補正を増やさない

clientXとclientYは表示領域を基準にする座標です。getBoundingClientRectのleftとtopを引き、装飾を置いた親の位置へ合わせます。今回の親にはborderを付けていません。borderを追加する場合や、親へscaleなどのtransformを付ける場合は、単純な差し算だけで正しいか見直します。

画面全体の固定カーソルなら、position: fixedとclient座標を組み合わせる別の設計になります。pageXを使う例をそのまま混ぜると、スクロール後にずれる原因になります。まず一つの座標系で合わせ、毎回不明な定数を足して直す構成にしないようにします。

will-changeやforce3Dを先に乱用しない

カクつく場合は、まずアニメーションの数、描画対象の大きさ、影やフィルター、毎フレームのDOM読み書きを調べます。すべての要素へwill-changeを付ければ解決するとは限りません。レイヤーやメモリーの負担も変わるので、必要な範囲へ限定します。

今回のコードではイベントの中で親の位置を読みます。大きなページで問題になる場合は、レイアウトが変わるタイミングで矩形を更新するなど、要件に合わせて計測頻度を減らす方法を検討します。ただし、スクロールで位置が変わる親に古い矩形を使い続けると、正確さを失います。

停止と再初期化を検証項目にする

初期化を十回繰り返し、演出を停止した後にポインターを動かしても更新されないことを確かめます。小画面、タッチ中心の端末、reduce設定では、装飾がなくても文章とボタンが使える状態にします。動く丸がリンクのクリックを奪わないようpointer-eventsもnoneにしています。

測定するなら、同じ端末と操作でPerformance記録やメモリーの変化を比較します。「GSAPだから速い」「quickToへ変えたから必ず改善する」と断定せず、残っている処理と実際の重い箇所を確認してから変更します。後片付けの境界を明確にすることは、性能だけでなく原因調査にも役立ちます。

スポンサーリンク

実装例:HTML・CSS・JavaScript

以下は独立したデモ用のコードです。既存のViteなど、npmパッケージを解決できる開発環境で npm install gsap を実行し、HTMLをbody内、CSSをスタイルシート、JavaScriptをmain.jsへ配置してください。main.jsはHTMLの末尾からtype="module"で読み込みます。WordPressの記事本文へそのまま実行用スクリプトを貼る例ではありません。

<section class="playground">
  <h1>ポインターを動かすと装飾が追従します</h1>
  <p>文章や通常のカーソルはそのまま利用できます。</p>
  <span class="dot" aria-hidden="true"></span>
</section>
<button id="mount" type="button">初期化し直す</button>
<button id="destroy" type="button">演出を停止して片付ける</button>
.playground { position:relative; min-height:20rem; overflow:hidden;
  padding:2rem; box-sizing:border-box; border:0; background:#0e100f; color:#fffce1; }
.dot { position:absolute; width:2rem; height:2rem; top:0; left:0;
  border-radius:50%; background:#0ae448; pointer-events:none; }
@media (hover:none), (pointer:coarse), (prefers-reduced-motion:reduce) {
  .dot { display:none; }
}
import { gsap } from "gsap";
const root = document.querySelector(".playground");
const dot = root.querySelector(".dot");
let dispose = () => {};
function mount() {
  dispose();
  const mm = gsap.matchMedia();
  mm.add("(hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference)", () => {
    gsap.set(dot, { xPercent: -50, yPercent: -50, x: root.clientWidth / 2, y: root.clientHeight / 2 });
    const xTo = gsap.quickTo(dot, "x", { duration: 0.25, ease: "power2.out" });
    const yTo = gsap.quickTo(dot, "y", { duration: 0.25, ease: "power2.out" });
    const move = (event) => {
      const rect = root.getBoundingClientRect();
      xTo(event.clientX - rect.left);
      yTo(event.clientY - rect.top);
    };
    root.addEventListener("pointermove", move);
    return () => root.removeEventListener("pointermove", move);
  });
  dispose = () => mm.revert();
}
mount();
document.querySelector("#mount").addEventListener("click", mount);
document.querySelector("#destroy").addEventListener("click", () => dispose());

サンプルを確認するときの条件

APIの使い方は公式資料と照合しています。掲載コードはGSAP 3.15.0とDOMを模した環境で読み込み・操作を確認しましたが、実ブラウザーでの見た目、タッチ操作、描画性能を保証するものではありません。採用前に対象ブラウザーと実機で確認してください。JavaScriptを無効にした状態でも、必要な内容と操作が残るかを確認します。

スポンサーリンク

参考資料

この記事を書いた人

Ryohei

Webエンジニア / アプリ開発者 / 技術ブログ運営者

福岡のWeb制作会社に勤務するWebエンジニアです。10年以上にわたりWeb制作・開発に携わり、これまでに100以上のWordPressサイトの構築・保守を担当してきました。Webサイト制作に加え、アプリ開発やAIを活用した開発にも取り組み、近年はWebセキュリティにも注力しています。

2015年から技術メディア「Into the Program」を運営し、実務や開発で得た知識をもとに、プログラミングの実装方法やWebサイトの運用・セキュリティ情報を発信しています。

主な分野
WordPress / PHP / JavaScript / アプリ開発 / Webサイトの運用・セキュリティ対策
資格・試験合格
情報セキュリティマネジメント試験
基本情報技術者試験
AWS認定ソリューションアーキテクト アソシエイト
メディア運営
2015年〜

記事の作成・更新について

セキュリティ記事は、ベンダーの公式アドバイザリやCVE・JVNなどの一次情報を参照し、出典と情報確認日を記載します。実環境での検証を行った場合は、その環境と確認範囲を明示します。重要な追加情報や誤りを把握した場合は、内容を確認して追記・訂正します。

スポンサーリンク

関連する記事

おすすめの書籍