【GSAP】ScrollTriggerを使って横スクロールさせる

操作は縦にスクロールさせる動きなのに、表示は横スクロールの動きになるサイトを時々見かけます。

このような動きは、GSAPのScrollTriggerを使用することで簡単に実装することができます。
ユーザーは縦スクロールの動きだけですべてのコンテンツを見ることができるので、操作性も抜群です。

横スクロールの実装方法について、順を追って説明していきます。

ScrollTriggerを使う準備をする

GSAPの公式サイトにも載っていますが、まずはHTMLのhead内に以下のファイルを読み込んでください。
ここではCDNで読み込む方法を載せましたが、他の方法で読み込みたい場合は公式サイトのInstallationをご覧になってください。

//GSAPのファイル
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/gsap.min.js"></script>

//ScrollTriggerプラグインのファイル
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12.5/dist/ScrollTrigger.min.js"></script>

次に、jsファイルに以下のコードを記述します。

gsap.registerPlugin(ScrollTrigger);

gsap.registerPlugin();は、GSAPのメソッドのひとつです。

このメソッドは、簡単に言えばGSAPにプラグインを認識させるためのものです。プラグインそのものを読み込む働きはないので、何らかの(CDNやその他の)方法でプラグインを読み込むのを忘れないようにしてください。

横スクロールさせる

コンテンツ全体を横スクロールさせる

See the Pen horizontal_scroll by Michi (@Michi_) on CodePen.

< HTML >

<section class="horizontal">
  <div class="panel">
    <p>section1</p>
  </div>
  ・
  ・
  ・
</section>

< CSS >

.horizontal{
  display: flex;
}
.panel{
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-shrink: 0;
  justify-content: center;
  align-items: center;
}

< java script >

gsap.registerPlugin(ScrollTrigger);

const section = gsap.utils.toArray(".panel");
const wrapper = document.querySelector(".horizontal");
const scrollLength = wrapper.offsetWidth;

gsap.to(section, {
  xPercent: -100 * (section.length - 1),
  ease: "none",
  scrollTrigger: {
    trigger: ".horizontal",
    pin: true,
    scrub: 1,
    snap: 1 / (section.length - 1),
    end: `+=${scrollLength}`,
    markers: "true",
  }
});

HTMLとCSSについて簡単に説明します。

まず、横スクロールしたいコンテンツ ” .panel ” を親となる要素 ” .horizontal ” で囲み、display: flex; で横並びにします。
” .panel ” には幅と高さを設定しています。

次に java script です。

const section = gsap.utils.toArray(".panel");
” panel ” のクラス名を持つ要素を配列として取得しています。

gsap.utils.toArray() の詳しい使い方についてはこちらの記事をご覧ください。

const wrapper = document.querySelector(".horizontal");
const scrollLength = wrapper.offsetWidth;

” horizontal ” の要素の幅を取得しています。

gsap.to(section, {
xPercent: -100 * (section.length - 1),

横スクロールする量を設定しています。
左側へスクロールするので、-100 、それに” .panel ” の数 -1 をかけています。

スクロール量は (” .panel” の幅)100% × ” .panel” の数 )ではなく、” .panel” の要素ひとつ分を引いたものを設定します。これが xPercent: -100 * (section.length - 1), の部分です。

ひとつめの要素は初めから表示されているので、 ” .horizontal ” の幅分を設定してしまうと、横スクロールの最後に要素ひとつ分の余白が表示されることになってしまうからです。

-100となっているのは、x軸のマイナス方向、つまり左方向にスクロールするためです。

ease: "none",
イージングはありません。

scrollTrigger: {
trigger: ".horizontal",
pin: true,
scrub: 1,
snap: 1 / (section.length - 1),
end: `+=${scrollLength}`,
markers: "true",
}
});

スクロールトリガーの設定は詳しくみていきましょう。

trigger: ".horizontal",
横スクロールのトリガーとなる要素を設定しています。

pin: true,
スクロールしている間、指定した要素が開始位置で固定されているように見えます。
固定できる要素は一つだけですが、その中に必要な数の要素を含めることができます。

このデモの場合、トリガーとなる".horizontal" が固定され、その中の".panel" の要素がスクロールされます。

pin: true, を設定した要素自体をアニメーション化することはできません。その代わりに、固定された要素内の要素をアニメーション化することができます。

scrub: 1,
scrub は、アニメーションの進行状況をスクロールバーに紐付けて、スクラバーのように機能させることができる機能です。

scrub: true を設定すると、アニメーションの進行状況とスクロールバーの動きが直接リンクします。スクロールバーの動きがそのままアニメーションに反映されるので、動きがカクカクとして不自然に感じることがあるかもしれません。

scrub: 1 のように、数値で設定すると、スクロールバーの動きが、設定した秒数の分だけ遅れてアニメーションに反映されます。動きがスムーズになるので、自然に感じられます。

snap: 1 / (section.length - 1),
snap を設定すると、ユーザーがスクロールを止めた後、設定した数値(0 から 1 までの間)の位置まで自動的に移動させることができるようになります。

例えば、snap: 0.1 とすれば、全体を0.1ずつ分割して、スクロールを止めた位置から1番近い場所まで移動します。

デモの場合は、” .panel ” 要素の数 -1 で分割することで、それぞれ要素の先頭に移動するように設定しています。

end: `+=${scrollLength}`,
スクロールトリガーの終了位置を設定します。
ここで設定した位置までくると、スクロールアニメーション、この場合は横スクロールが終了します。

end位置は任意の場所に設定することができますが、横スクロールする幅の分と同じ長さを設定することで、ユーザーが操作する縦スクロールと実際に表示される横スクロールが同期したように見えるので、おすすめです。

このデモでも、上の画像のように ” .horizontal ” 全体の width を設定しています。

縦スクロールの途中で横スクロールになる

See the Pen horizontal_scroll-2 by Michi (@Michi_) on CodePen.

gsap.registerPlugin(ScrollTrigger);

const section = gsap.utils.toArray(".panel");
const wrapper = document.querySelector(".horizontal");
const scrollLength = wrapper.offsetWidth;

gsap.to(section, {
  xPercent: -100 * (section.length - 1),
  ease: "none",
  scrollTrigger: {
    trigger: ".horizontal",
    pin: true,
    anticipatePin: 1,
    scrub: 1,
    snap: 1 / (section.length - 1),
    start: "top top",
    end: `+=${scrollLength}`,
  invalidateOnRefresh: true,
    markers: "true",
  }
});

先ほどのデモは、サイト全体が横スクロールで動くというものでしたが、こちらのデモは、縦スクロールのサイトの中に、一部横スクロールの部分が入っているというものになります。

HTMLとCSSは同じものを使用しているので、説明は割愛させていただきます。

java script に関しても、基本的に同じものを使用していますが、2行追加したコードがありますので、そちらの説明をしていきますね。

anticipatePin: 1,
大きなパネルを固定するときに、素早くスクロールすると、固定にわずかな遅れが生じるように見えることがあります。この現象に対する対応策がこのプロパティになります。ScrollTrigger にスクロール速度を監視させてピンを予測させ、少し早めにピン留めを適応することで遅れが生じないようにすることができます。

基本的にはanticipatePin: 1, を記述すれば問題ありませんが、数値を増減することでピンの固定をどれくらい早く実行するのかを制御することができます。また、公式サイトによれば、多くの場合でanticipatePin は必要ないとされています。必要に応じて使用していただければと思います。

invalidateOnRefresh: true,
画面サイズを変更するなどしてスクロール値が変更される場合に、内部的に記録された値をリセットして正しくアニメーションするように再計算するために記述しています。

ピン留めせずに横スクロールする

See the Pen horizontal_scroll-3 by Michi (@Michi_) on CodePen.

gsap.registerPlugin(ScrollTrigger);

const section = gsap.utils.toArray(".panel");

gsap.to(section, {
  xPercent: -100 * (section.length - 1),
  ease: "none",
  scrollTrigger: {
    trigger: ".horizontal",
    scrub: 1,
    start: "top bottom",
    end: "bottom top",
    markers: "true",
  }
});

このデモは、縦スクロールの中に一部横スクロールの部分を入れたものになりますが、今までのデモと異なりピン留めをしていません。

コードを見ていただくと、pin: true, の記述がないことが確認できると思います。

パネルをピン留めすると、横スクロールの部分が最初から最後まで画面上の指定した場所に留まり続けますが、ピン留めしないことで横スクロールしつつも画面下部から上部へと移動していきます。

ピン留めした場合は、画面に残り続けるのでコンテンツの中身をしっかり見てもらいたいときに最適です。

ピン留めしない場合は、コンテンツの中身をしっかり見てもらいたいときには不向きですが、例えば画像などを配置して、背景のアクセントのように使うというのはありかなと思います。

まとめ

本記事ではScrollTriggerを使って横スクロールさせる方法を説明しました。

ピン留めするかしないかでガラッと印象が変わってくるなど、面白いアニメーションですよね。
ぜひ皆さんもいろいろ試して使いこなしてみてください!

参考文献:

コメント

タイトルとURLをコピーしました