GSAPのスクロールアニメーションライブラリ「ScrollTrigger」入門

最後参考にも記載していますが、以下は[【2020年最新】GSAPの「ScrollTrigger」を使って爆速でスクロールアニメを実装する](https://www.to-r.net/media/scrolltrigger/)を構成の参考にさせていただき、[公式ドキュメント](https://greensock.com/docs/v3/Plugins/ScrollTrigger)を要約したものになります。

申し訳ありません、お手数ですが<font color="Red">本記事の中の codepen は倍率を ×0.5 にしてご覧ください</font>。

#ScrollTrigger とは
GSAP(GreenSock Animation Platform)から、2020年5月にリリースされた、「スクロールアニメーション」のためのプラグインであり、とても簡単な記述によって複雑なスクロールアニメーションを実現することができます。

昨今、様々なスクロールアニメーションのためのライブラリやAPIが使用されていますが、その中でも一線を画する機能を備えています。

##ScrollTriggerの特徴
主な特徴として以下が上げられると思います。

- アニメーションを特定の要素にリンクさせることができる
- **マーカー**によってデバックや作成が容易
- **スクロールにリンクした動き**を簡単に作成できる
- 特定のスクロール位置の間で要素を固定できるピン留め機能
- コールバックの充実

それぞれ見ていきます。

##使い方
最初に一番簡単にScrollTriggerを使用してアニメーションさせてみます。

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="GRjEEzL" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="GRjEEzL">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/GRjEEzL">
  GRjEEzL</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

黒いボックスが画面中央に来た時にアニメーションが発火したかと思います。

```javascript

gsap.to('.box', { // .box => アニメーションさせる要素
  x: 400, // アニメーションの内容
  scrollTrigger: {
    trigger: '.box', // トリガーとなる要素（アニメーションの開始、終了の位置決定に使用する）
    start: 'center center', // アニメーションの開始位置の指定
  }
});
```
上記のアニメーションはこちらのコードにあるように、
1. アニメーションさせる要素を指定
2. アニメーションの内容を指定
3. トリガーとなる要素を指定
4. アニメーションの開始位置の指定

これだけで実装しています。
さて、ここでわかりにくいのが **start** の指定方法ですね。

###アニメーションの範囲指定
```javascript

start: 'center center', 
```
上記コードで言うと
<font color="Red">左側の center が「トリガーとなる要素」における位置</font>
<font color="blue">右側の center が「ブラウザの画面内」における位置</font>
をそれぞれ指定しています。
指定の方法は色々あり、例えばtop、center、bottomと指定すると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562979/715454fd-52de-ca2e-f5d4-9434fd89aaf8.png)
画像におけるそれぞれの位置を指定することができ、他にも
「20%」「−80%」「top+=300px」「bottom-=50%」など色々な指定方法により柔軟に対応することが可能です。

これら、指定した2つの位置が交差したタイミングでアニメーションが発火します。
つまり上記サンプルの場合は、<font color="Red">.box の中心（center）</font>が、<font color="blue">画面の中心（center）</font>と交差した時に要素を右に400px動かす、という指定をしていることになります。

と言っても、いやどこなんだよ、わかりづらいわ、となりますよね、、、
大丈夫です、このわかりずらさを見事に解消してくれる**マーカー機能**があります。

###マーカー
<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="mdrwpMd" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="how to markers">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/mdrwpMd">
  how to markers</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

```javascript

gsap.to('.box', {
  x: 400,
  scrollTrigger: {
    trigger: '.box',
    start: 'center center',
    markers: true,  // マーカーを表示させる
  }
});
```

<font color="Green">緑</font>と<font color="Red">赤</font>のマーカーが表示されていると思います。
表示されているマーカー<font color="Green"> start </font>と<font color="Green"> scroller-start </font>が交差したタイミングでアニメーションが開始します。
ここでは **start** は「トリガーとなる要素」における指定位置を表し、**scroller-start** は「ブラウザの画面内」における指定位置を表します。

これでアニメーションの開始位置が非常にわかりやすくなりましたよね。
え、**end** なるものがある？はい、この後説明します。（説明するまでもなさそうですが、、）


##ScrollTriggerによって簡単に実装できる複雑な機能
ここまででScrollTriggerを触る上での最低限の説明はできたかと思いますので、ここからScrollTriggerを使用することで簡単に実装できる機能を紹介していきます。

###スクロールにリンクした動き

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="LYRLemv" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="LYRLemv">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/LYRLemv">
  LYRLemv</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

```javascript

gsap.to('.box1', {
  x: 400,
  scrollTrigger: {
    trigger: '.container',
    start: 'center 70%',
    end: 'center 30%', // アニメーションの終了位置の指定
    scrub: true, // スクロールの進捗とアニメーションの進捗をリンクさせる
  }
});
```

上記のサンプルでは、
.container の中心が、画面の（上から）70%の位置と交差した時にアニメーションが開始され、
.container の中心が、画面の（上から）30%の位置と交差した時にアニメーションが終了し、
スクロールに合わせてこれが繰り返されます。（x:0 〜 x:400を行き来する）

**scrub** の値に数値を指定することで遅延させることができ（スムーズに追いつきます）、数値が大きくなるほど遅延が大きくなります。
またこの際、数値は秒単位で指定します。
上記サンプルの下のボックスには scrub に「２」を指定しているので、2秒遅延してスムーズに追いつくアニメーションになります。

###ピン留め

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="XWjgVvo" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="how to pin">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/XWjgVvo">
  how to pin</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

```javascript

gsap.to('.box', {
  x: 400,
  scrollTrigger: {
    trigger: '.container',
    start: 'top center-=20%',
    end: 'bottom center-=100px',
    markers: true,
    scrub: true,
    pin: true, // start から end で指定した間、トリガー要素を固定表示させる
  }
});
```

**pin** を「true」とすること、start から end で指定した間をスクロールした時に、トリガー要素を固定表示させることができます。

基本はこれだけで大丈夫です。
ただ、色々な場合に備えて複数の補助設定が可能になっています。

|properties  | |
|---|---|
|pinSpacing |pin を設定するとデフォルトでは、固定表示が終わったタイミングで次のコンテンツが追いつくように、他の要素を下に押し下げるために下方にパディングが設定されます。<br>また false にすることでパディング無しにできます。<br>( margin にするとパディングではなくマージンで設定される)|
|anticipatePin |基本 1 に設定。（デフォルトは 0 ）<br>pin を設定した際、素早くスクロールしたときにピン留めが少し遅れることがあります。anticipatePin に数値を設定することで少し早めにピン留めさせることで解決させることができます。|

##コールバック
便利なコールバックを一部紹介します。

|callback | |
|---|---|
|onEnter |スクロール位置が start を超えて前方に移動したときのコールバック|
|onEnterBack |スクロール位置が end を過ぎて後方に移動したときのコールバック|
|onLeave |スクロール位置が end を超えて前方に移動したときのコールバック|
|onLeaveBack |スクロール位置が start を過ぎて後方に移動したときのコールバック|
|onRefresh |リフレッシュ（通常はリサイズイベント）が発生した時に、ScrollTriggerに全ての位置を再計算させるためのコールバック|
|onUpdate |スクロールトリガーの進捗状況が変化するたびに呼び出されるコールバック|
|onToggle |スクロール位置が start または end を超えた時のコールバック|

これらのコールバックは、ScrollTriggerインスタンスを受け取ることができます。
ScrollTriggerインスタンスのプロパティを一部紹介します。

|properties, methods| |
|---|---|
|progress |進行状況（ start から end で指定した間での進行状況を０（開始）〜１（終了）で取得 ）|
|direction |1 を前方、-1 を後方としたスクロールの方向を取得|
|isActive |スクロール位置が start から end で指定した間にある場合にのみ true になる|
|getVelocity()|スクロール速度をピクセル/秒単位で取得|

下記にそれぞれのサンプルを置いております。

**onEnter, onEnterBack, onLeave, onEnterBack**

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="GRjEQEm" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="how to callback 01">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/GRjEQEm">
  how to callback 01</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

**onUpdate**
表示は上から progress, direction, isActive, getVelocity()

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="YzGQerp" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="how to onUpdate()">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/YzGQerp">
  how to onUpdate()</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

**onToggle**
サンプルとして発火の度にインクリメントさせています

<p class="codepen" data-height="500" data-theme-id="light" data-default-tab="css,result" data-user="watanabe-hazime" data-slug-hash="zYKzRpO" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="zYKzRpO">
  <span>See the Pen <a href="https://codepen.io/watanabe-hazime/pen/zYKzRpO">
  zYKzRpO</a> by watanabe (<a href="https://codepen.io/watanabe-hazime">@watanabe-hazime</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://production-assets.codepen.io/assets/embed/ei.js"></script>
<font color="Gray">倍率を ×0.5 にしてご覧ください</font>

##その他
- timelineと組み合わせることもできます
- 更新のスロットリング、スクロール時の労力を最小限に抑えるための交差点の事前計算、変換の活用、GPU を利用するための要素のレイヤー化など、あらゆる種類のテクニックを使用してパフォーマンスを最大化、最適化されています。
- （当たり前ですが、、）GSAPをベースに構築されています。
- もちろん、IE11でも問題なく動きます。（私が試した範囲では問題ありませんでした。）

##所感
- 普通のクラスの操作や簡単な実装であれば、スクラッチや IntersectionObserver などでいいかと思いました。
複雑な処理（スクロールにリンクした動き、ピン留め）など、上記のものでは実装が大変な場合や、面倒な場合には、ScrollTrigger を使用することでとても簡単に実装できるものが多いかもしれません。
- ファイルサイズも大きい訳ではありませんが、GSAPも一緒に入れる必要がありますので、GSAPを入れている場合（入れたい場合）で複雑なスクロールアニメーションを実装する必要がある場合には、積極的に採用してもいいかもしれませんね。

##参考
[【2020年最新】GSAPの「ScrollTrigger」を使って爆速でスクロールアニメを実装する](https://www.to-r.net/media/scrolltrigger/)
[ScrollTrigger公式ドキュメント](https://greensock.com/docs/v3/Plugins/ScrollTrigger)