こんにちは。フロントエンドエンジニアになりたてのぼこです。
この記事ではGSAPというアニメーションライブラリを使って、ページが途中から横にスクロールするような表現を実装してみたいと思います。
GSAPを知らない方にも読んでいただけるよう、導入方法から説明します。
技術系の記事を書くのは初めてなので至らない点が多いかとは思いますが、どなたかの助けになれば幸いです。
今回作るデモ
さっそくですが、今回紹介するデモがこちらです。

実際の操作はただ下へ下へスクロールしているだけですが、二つ目のセクションではスクロールに対して真横にページが動いているかと思います。
GSAPを使えばこんなことも簡単にできてしまうんですね。
ではでは解説に参ります。
GSAPってなに
まずはGSAPとはそもそも何なのかについてです(デモの解説だけ見たい方は飛ばしちゃってください)。
概要
GSAP(GreenSock Animation Platform)は、GreenSock社が開発している軽量で多機能、そして直感的に扱いやすい超スゴいJavaScriptアニメーションライブラリです。
GSAP(ジーサップ)と読むらしいです。
JavaScriptでアニメーションを制御しますが、JavaScriptの知識がなくても扱えてしまうくらい、簡単にアニメーションが作れます。
TweenMaxとの違い
GSAPは以前まで、その機能によってライブラリがいくつかに分かれていました。
TweenMaxなどはそのうちの一つで、現時点(2021年5月)での最新バージョンであるGSAP3から、それらが一つにまとめられて使いやすくなったという感じですね。
そのため、ざっくりいうとバージョンの違いで本質的には同じものを指していますが、書き方など変更点はいくつか存在しますので、参考にする際は注意しましょう。また、本記事で扱うデモはGSAP3で実装しています。
なぜGSAPを使うのか
GSAPの魅力はアニメーションを簡単に実装できてしまうことももちろんですが、他にも開発する上で嬉しいことがいっぱいあります。
パフォーマンスに優れている
今回扱うのはGSAPのScrollTriggerという機能ですが、ScrollTriggerでは「アニメーションの対象が画面内に入ってきたときだけ処理を実行する」といった最適化があらかじめ行われています。
どういうことかというと、jQueryなどを使った従来のスクロールアニメーションは、スクロールのたびに処理が毎回実行されていました。そうすると、アニメーションの内容によってはサイトの動作が重たくなってしまいます。
画面外の見えていない要素まで常に動かすのは無駄なので、画面から出たら処理を行わないなどの制御が求められるのです。しかしScrollTriggerはそのようなことを最初からやってくれており、使う側はアニメーションのデザインに集中できます。
デバッグが簡単
これもScrollTriggerの話になりますが、スクロールに紐付くアニメーションはタイミングの調整が難しかったりします。そんなときに使えるのが「マーカー機能」です。

アニメーションの開始と終了のタイミングを視覚的にわかりやすくするマーカーがデフォルトで備わっていて、オプション(後ほど紹介します)を指定するだけで表示できます。要素がどのタイミングでアニメーションし始めるかなどがとっても分かりやすくなるので、作業がしやすいです。
実際に使ってみる
それでは、実際にGSAPを使ってみましょう。
導入
CDNの場合
とりあえず手軽に始めたい場合はCDNが便利です。
HTMLファイル内のheadタグの中に以下の二つを追記しましょう。
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.6.1/ScrollTrigger.min.js"></script>
一つ目がGSAPのコアとなるファイルの読み込み、二つ目が今回使うScrollTriggerの読み込みです。これで準備が整いました。
*執筆時点(2021年5月)ではバージョンが3.6.1となっていますので注意してください。最新バージョンは公式サイトで確認できます。
npm / yarnの場合
npmやyarnを用いる場合はパッケージをインストールし、JavaScript内でimportします。
まずはお使いの環境に合わせてnpm i gsap もしくは yarn add gsapしてください。
そしてモジュールをimportします。
import gsap from 'gsap';
import { ScrollTrigger } from "gsap/ScrollTrigger";
また、npmやyarnでScrollTriggerなどの機能を扱う場合は、以下のコードを追記してプラグインの登録をする必要があります。
gsap.registerPlugin(ScrollTrigger);
詳細は公式サイトにあるのでこちらも見てみてください。
デモの解説
See the Pen
GSAP Side Scroll by Bokoko33 (@bokoko33)
on CodePen.
実際のソースがこちらになります(表示サイズの関係で少し見づらいので、実際にデモを触る場合は右上のEDIT ON CODEPENをクリックしてCodePen上で開いてください)。
HTML / CSS
HTMLやCSSについては重要な点のみ抜粋して解説したいと思います。
横スクロールのリストの箇所を見てください。
<div class="side-scroll-list-wrapper">
<ul class="side-scroll-list">
<li class="side-scroll-item">
<div class="side-scroll-card">Card</div>
<p class="side-scroll-text">テキストが入りますよ</p>
</li>
<!-- 省略 -->
<li class="side-scroll-item">
<div class="side-scroll-card">Card</div>
<p class="side-scroll-text">テキストが入りますよ</p>
</li>
</ul>
</div>
.side-scroll-list-wrapper {
position: relative;
width: 100%;
height: 700px;
}
.side-scroll-list {
position: absolute;
display: flex;
}
今回横スクロール部分のカードレイアウトは、横並びのリストを使っています。ポイントは、リストを覆うラッパーを作り、リストそのものはposition: absolute;にしているところです。
横幅をはみ出すような長いリストをラッパーを基準に左右に動かすイメージです。
また、リストそのものは、position: absolute;とすると高さがカウントされなくなるので、heightやpaddingを使ってラッパーに高さを入れておきましょう。
JavaScript
いよいよ本題です。コードを見てもらうとわかると思いますが、とってもシンプルな記述で済んでいます。GSAPってすごい。
const el = document.querySelector('.side-scroll-list');
gsap.to(el, {
xPercent: -80,
ease: 'none',
scrollTrigger: {
trigger: '.side-scroll',
start: 'top top',
end: `+=${el.clientWidth}`,
scrub: true,
pin: true,
},
});
上から順に見ていきましょう。
const el = document.querySelector('.side-scroll-list');
gsap.to(el, {
xPercent: -80,
...
});
まずはアニメーションさせる横スクロールのリストを取得し、変数に入れます。そしてgsap.to()の一つ目の引数に指定すると、その要素を動かすことができます。
今回はリスト全体の横幅を後で使いたいので変数に代入しましたが、基本的には以下のように、クラス名を直接入れて使うことができます。
gsap.to('.side-scroll-list', {
xPercent: -80,
...
});
また、GSAPには様々なメソッドが用意されていて、今回使用するgsap.to()は指定した状態へ変化するといった意味合いになります。つまり、以下のようにするとtextというクラス名を持った要素をx方向に100px動かすことができます。
gsap.to('.text', {
x: 100,
});
これがGSAPの基本的な構文です。今回のデモでは、リストが画面幅に合わせて最後まで正しく横に動くよう、xPercentという相対値を扱えるプロパティを使っています。
xPercent: -80とすることで、リストの長さの80%分、左側に動かすという意味になります(今回-80という数値は感覚で決めています。理想の動きになるよう数値を調節してみてください)。
続いて、今回の肝であるScrollTriggerの部分です。
scrollTrigger: {
trigger: '.side-scroll',
start: 'top top', // 要素の上端(top)が、ビューポートの上端(top)にきた時
end: `+=${el.clientWidth}`, // リストの横幅分移動したら終わり
scrub: true, // スクロールに同期させる
pin: true, // アニメーション中に要素を固定
},
});
ScrollTriggerを使う場合、オブジェクトをさらにネストする形でScrollTrigger用のパラメータを設定します。
ちなみに、冒頭で紹介したマーカー機能は、ここにさらに
markers: true
と追記すると使用できます。
trigger
triggerでは、その名の通りアニメーション発火の引き金となる要素を指定します。今回のアニメーションでは横スクロールするセクションを指すクラス‘.side-scroll’を指定します。
そうすると、このアニメーションはside-scrollセクションが画面内に入ってきたときに実行される、という意味になります。
start
startには、triggerに指定した要素が具体的に画面のどの部分に入ったらアニメーションを発火するのか、を指定できます。
今回のデモでは‘top top’となっているので分かりづらいですが、以下のように考えます。
start: '①triggerの要素のどの部分? ②画面のどの部分?',
つまり、今回はtriggerであるside-scrollセクションの一番上が、画面の一番上に来たらという意味になりますね。
また、top以外にもbottomやcenterといった位置指定ができる他、例えば「画面の上から30%くらいの位置に来たら」としたい場合は②の値を30%とすることで実装できます。便利ですね。
end
startがアニメーションの開始タイミングを指定するのに対し、endは終了タイミングを指定します。
startで指定したようなtopなどを使って画面内での位置を元に制御することもできますが、今回はリストの横幅分だけアニメーションさせたいのでこのような書き方にしています。
テンプレート文字列を使っていますが、以下と同じ意味です。
'+=' + el.clientWidth
設定したアニメーションを一度だけ発火する場合はstartだけで大丈夫ですが、今回はスクロールの量に連動させるためendも用いています。
scrub
scrubをtrueにすることで、アニメーションはスクロールに同期します。今回はスクロールに追従するアニメーションなのでtrueにしますが、例えば「ここまでスクロールしたら画像をふわっと表示する」といったようなアニメーションの場合は、scrubはいらなくなります。
pin
こいつが今回のポイントであるpin機能で、要素をピン留めしたかのように画面に固定します。つまり、今回の横スクロールデモは、pinによって画面内にセクションを固定することで、その間はスクロールしても下には行かず、代わりにとリストが横へ動くため横スクロールしているように見える、というわけですね。
こんなに複雑なことがこんなにシンプルな記述で実装できてしまうわけです。すごい。
デモの使いどころと注意点
今回実装した横スクロール風アニメーションは、ボリュームのあるカードレイアウトをコンパクトに収めたいときなどに使えます。
通常そのようなケースではカルーセルスライダーと呼ばれるデザインがされることがほとんどですが、このデモのポイントは通常の上下スクロール動作のみですべてのカードを見せることができる点です。ドラッグやスワイプ、ボタンクリックなどでスライダーを左右に送らなくてもいいのがいいところですね。
しかし、使いすぎには注意です。すべてのカードを見せることができるということは、今回のようにセクションの途中に入れて使う場合、ユーザーはすべてのカードを見るまで下に行くことができないということになります。
コンパクトにできるからといって詰め込みすぎると、見る人をイライラさせてしまうかもしれないので気をつけましょう。
おわりに
GSAPってすごいなあと思っていただけたのではないでしょうか。実は僕もこの記事を書くタイミングで初めて使ってみたのですが、すでにGSAPなしでは生きていけません(笑)。
あまり王道なデモではありませんでしたが、既にGSAPを知っている方にも、こんなこともできるんだという新たな発見になれば嬉しいです。
最後まで読んでいただきありがとうございます! また次の記事でお会いしましょう。
LIGはWebサイト制作を支援しています。ご興味のある方は事業ぺージをぜひご覧ください。