【GSAP】matchMedia()を使ったレスポンシブ対応の方法を紹介

GSAP

GSAPでアニメーションを作るとき、そのサイトがレスポンシブ対応していればアニメーションもレスポンシブ対応をしたくなるものです。

GSAPにはmatchMedia()という便利な機能があり、これを使うことで画面サイズに応じて違うアニメーションを実行させることができます。

この記事ではgsap.matchMedia()を使ってレスポンシブ対応する方法を紹介しています。同時に思い通りの動きができないときに確認するとよさそうなポイントも挙げていますので制作の参考にしていただけたら幸いです。

基本的には私が公式サイトなどを参考に勉強したことを整理した内容になっていますが、経験上なかなか思い通りに動かなく悩む時間が多い部分かと思います。

gsap.matchMedia()を使ったレスポンシブ対応方法

まず、基本構文は次のような形になります。この例では、ブレークポイントを1024pxとして上下2パターンを書く方法です。シンプルに1024px以下の場合と、1025px以上の場合を設定します。

$(function(){
  let mm = gsap.matchMedia();

  mm.add("(max-width: 1024px)", () => {
    // ここに1024px以下のときのコードを書きます
  });

  mm.add("(min-width: 1025px)", () => {
    // ここに1025px以上のときのコードを書きます
  });

});

最初にgsap.matchMediaオブジェクトを作ります。変数はMatchMediaの頭文字を使ってmmとしていますが、ここは何でも良いです。

続けて、mmオブジェクトのadd()関数を使ってメディアクエリの条件を追加していきます。メディアクエリの文字列はCSSなどで指定するときと同じです。

この構文によって、特定のメディアクエリがマッチしたときだけ実行する処理(関数)を設定することができます。

一方で画面サイズが変わりメディアクエリがマッチしなくなったとき、その関数の実行中に設定されたGSAPのアニメーションやScrollTriggerが自動でリセットされます。

ブレークポイントを超えれば、自動でアニメーションを変えてくれるので便利でありがたいです♪

gsap.matchMedia()が正しく動かないときに確認するポイント

gsap.matchMedia()が動かない場合は、以下のような点がチェックできるかと思います。

GSAPのバージョンを確認する

ブラウザの開発ツールで以下のようなエラーが発生している場合。

【 Uncaught TypeError: gsap.matchMedia is not a function 】

まずGSAPのバージョンを確認します。matchMedia()が使えるバージョンは、「3.11.0」以降です。2022年の夏くらいから追加された比較的新しい機能なので、古いバージョンファイルを使いまわしていると動かない原因となります。

古いバージョンを読み込んでいる場合は、3.11.0以上のバージョンを読み込むことで解決できます。

ブレークポイントを増やしたらmatchMedia()が正しく動かない

ブレークポイントを増やした場合にうまく動かない例です。

最初に紹介したサンプルはブレークポイントが1つで処理もシンプルでしたが、スマホ用・タブレット用・パソコン用など3つ以上のブレークポイントを設定する場合は注意が必要です。

以下が上手く動かない例です。

let mm = gsap.matchMedia();

mm.add("(min-width: 600px)", () => {
  // 600px以上のときは上下に動かす
  gsap.to(".box", { yPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
});

mm.add("(min-width: 769px)", () => {
  // 769px以上のときは左右に動かす
  gsap.to(".box", { xPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
});

mm.add("(min-width: 1025px)", () => {
  // 1025px以上のときは回転させる
  gsap.to(".box", { rotation: 360, duration: 2, ease: "none", repeat: -1 });
});

CSSのメディアクエリの書き方と比べると問題がないように見えますが、これを実行すると想定した動きにはならないと思います。

何が起きるのか。まず600px未満でアニメーションなしなのはOK。600px以上になると上下アニメーションが開始するというのもOK。問題は769px以上のとき。

画面サイズが769pxより大きくなると、600px以上で設定したアニメーションと769px以上で設定したアニメーションが混ざります!

さらに1025px以上の画面になると、回転も含めた全てのアニメーションが合体します笑

gsap.matchMedia()を使う場合は、次のように、上限と下限のどちらも書いてあげる必要があります。

let mm = gsap.matchMedia();

mm.add("(min-width: 600px) and (max-width: 768px)", () => {
  // 600px以上768px以下のときは上下に動かす
  gsap.to(".box", { yPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
});

mm.add("(min-width: 769px) and (max-width: 1024px)", () => {
  // 769px以上1024px以下のときは左右に動かす
  gsap.to(".box", { xPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
});

mm.add("(min-width: 1025px)", () => {
  // 1025px以上のときは回転させる
  gsap.to(".box", { rotation: 360, duration: 2, ease: "none", repeat: -1 });
});

これで意図した通りにアニメーションの切り替えができるかと思います。

ScrollTrigger.matchMedia()について

GSAPのScrollTriggerの機能の中には、gsap.matchMedia()と同じ目的を達成することができる「ScrollTrigger.matchMedia()」があります。

同じく、メディアクエリと一緒に画面サイズに応じた処理を書き分けられるのですが…

公式サイトによると、Ver3.11.0でgsap.matchMedia()が実装されたことで、こちらのScrollTrigger.matchMedia()は非推奨となったということです。

[DEPRECATED in favor of gsap.matchMedia() in 3.11.0+]

https://greensock.com/docs/v3/Plugins/ScrollTrigger/static.matchMedia()

私も今まではScrollTriggerの方を使っていましたが、今後は切り替えていこうかなと考えています。

まとめ

GSAPのmatchMedia()を使って、レスポンシブ対応を実現する方法を紹介しました。

最後にHTML全体を載せておきます。コピペして使っていただいても構いませんが、シンプル重視のコードなので動作の参考程度にしていただけたらと思います。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SAMPLE</title>
  <style>
    .box { width: 100px; height: 100px; margin: 50px; border-radius: 10px; background: lightgray}
  </style>
</head>
<body>
  <div class="box"></div>

  <script src="//code.jquery.com/jquery-3.6.0.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/3.11.0/gsap.min.js"></script>
  <script src="//cdnjs.cloudflare.com/ajax/libs/gsap/3.11.0/ScrollTrigger.min.js"></script>
  <script>
    let mm = gsap.matchMedia();

    mm.add("(min-width: 600px) and (max-width: 768px)", () => {
      // 600px以上768px以下のときは上下に動かす
      gsap.to(".box", { yPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
    });

    mm.add("(min-width: 769px) and (max-width: 1024px)", () => {
      // 769px以上1024px以下のときは左右に動かす
      gsap.to(".box", { xPercent: 50, yoyo: true, duration: 1, ease: "none", repeat: -1 });
    });

    mm.add("(min-width: 1025px)", () => {
      // 1025px以上のときは回転させる
      gsap.to(".box", { rotation: 360, duration: 2, ease: "none", repeat: -1 });
    });
  </script>
</body>
</html>

ぜひ素敵なホームページを作成してくださいね♪