複数の要素を順番に動かしたり、スクロールの位置に応じてアニメーションを発火させたり、といった少々複雑なアニメーションを実装するのに便利なGSAP。
この記事ではGSAPを使う上でもっともよく出てくる「Tween」「Timeline」「ScrollTrigger」について、複雑なアニメーションに取り組む前に覚えておきたい基本をまとめました。
GSAPとは?
Green Sock Animation Platform略してGSAP(ジーサップ/ジーエスエーピー)とは、高機能なアニメーション実装用のJavaScriptライブラリ。
基本となるGSAP本体のほかに、ScrollTriggerなどのプラグインが存在して、それらを組み合わせることで様々な表現ができる。
よく使う「Tween」「Timeline」「ScrollTrigger」の基本
GSAPを使って何かしらのアニメーションを作成しようとするとき、多くの場合は「Tween」「Timeline」「ScrollTrigger」の3つを組み合わせて利用します。
それぞれどんなものかを簡単に説明します。
Tween
Tweenはbetween(あいだ)を由来とする言葉で、状態Aから状態Bへ変化するアニメーションの事を指します。

Tweenの作成には gsap.to() gsap.from() gsap.fromTo() のいずれかを使います。
gsap.to()
(CSSなどで設定した)元の状態から、指定した状態へ変化するTweenを作成します。
とくに何も条件がなければいったんこれでTweenの作成を試みます。
gsap.to(".star", {color:"blue", scale:1, duration:3})gsap.from()
指定した状態から、(CSSなどで設定した)元の状態へ変化するTweenを作成します。
フェードインなど、非表示状態から表示するアニメーションに向いています。
gsap.from(".star", {color:"red", scale:3, duration:3})gsap.fromTo()
指定した状態(ひとつめ)から、指定した状態(ふたつめ)へ変化するTweenを作成します。
再生開始タイミングによって「元の状態」を利用すると動作がおかしくなる時におすすめです。
gsap.fromTo(".star",{color:"red", scale:3},{color:"blue", scale:1, duration:3})()の中身の見方

●ターゲット
()の中の最初に指定するもの(第1引数)で、「何を」動かしたいかを指定します。
- 文字列(class名などのCSSセレクタ)
- 変数(document.querySelectorなどを使ってHTML要素や配列、NodeListを入れたもの)
が指定できます。
●varsオブジェクト
()の中で2つ目に指定するもの(第2引数)で、「どのように」動かしたいかを指定します。
- アニメーションしたいあらゆるプロパティ
- アニメーションについての特別な設定
- アニメーションの長さ
- イージング
- リピートするかどうか
- などなど
 
が指定できます。
Timeline
Timelineは、複数のTweenのあつまり。
たとえば以下の例だと3つのfromTweenをまとめたTimelineが作成されます。

gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2})
  .from(".square",{scale:0,opacity:0,duration:3})※補足: . でつなげるメソッドチェーン
上記の .timeline() や.from() の後には ; がありません。
改行してあるので分かりにくいですが、これはgsap.timeline().from().from().from() とつなげているのと同じ状態です。
こうすると、ひとつのtimeline() に対して、3つのfrom()の処理を登録することができます。
Timelineを使う理由
一連のアニメーションをひとつのTimelineにまとめるメリットには、以下のようなものがあります。
- いずれかのTweenの長さが変わったとき、各Tweenの再生開始タイミングが自動で調整される
- 一連のアニメーション全体に対して一時停止したり、再開したりすることが簡単
「Aの後にB、Bと同時にC」というように、いくつかのTweenを同時または連続して再生したいときはTimelineにまとめましょう。
ScrollTrigger
ScrollTriggerはGSAPのプラグインです。
- 要素が画面に入ったら、アニメーションする
- スクロール位置に応じて徐々にアニメーションが進行する
というような動きをする場合に使います。
プラグインの利用準備
CDN経由で利用する場合はScrollTrigger.min.js を追加で読み込む必要があります。
npm で利用している時は gsap.registerPlugin(ScrollTrigger) のように設定しておきます。
ふたつの使い方があるScrollTrigger
ScrollTriggerには大きく分けて2つの使い方があり、検索して出てきたコードをコピペするときに混乱しやすいです。
しかし、どちらの使い方も {} の中の書き方は基本的に同じだと覚えておきましょう。

使い方1: TweenやTimelineのvarsオブジェクトに指定する
gsap.to() や gsap.timelime() などの{} のなかに scrollTrigger:{} で指定することで、TweenやTimelineにScrollTriggerを設定することができます。
※ScrollTriggerを設定する=スクロール位置に応じてアニメーションを再生する
ただし、複雑な動作を実現するなら、次に述べる「単独で宣言する」方法を使うことをお勧めします。
gsap.to(".star", {
  color:"blue",
  scale:1,
  duration:3,
  scrollTrigger: {
    trigger:".hoge",//この要素が画面内に入ったときに再生
    markers:true, //startとendの位置を確認できるデバッグ用マーカー
  }
})
gsap.timeline({
  scrollTrigger: {
    trigger:".hoge",//この要素が画面内に入ったときに再生
    markers:true, //startとendの位置を確認できるデバッグ用マーカー
  }
})
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2})
  .from(".square",{scale:0,opacity:0,duration:3})使い方2:単独で宣言する<おすすめ>
TweenやTimelineとは別途単独でScrollTriggerを宣言することもできます。
以下のようにScrollTriggerを定数に入れておくと、あとから.kill() などScrollTriggerに対して何らかの処理を加える(コールバックを使う)ときにとても便利です。
const myTween = gsap.to(".star", {color:"blue", scale:1, duration:3});
const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",//この要素が画面内に入ったときに再生
    animation: myTween,//TweenとTimelineどちらを設定してもOK
    markers:true, //startとendの位置を確認できるデバッグ用マーカー
})Tweenでできること
イージング(緩急)をつける
ease を指定することで、Tweenに緩急をつけることができます。
easeの設定値の中には純粋な緩急いがいに、bounce のように弾むような特別な動きをするものもあります。
gsap.to(".star",{x:200,duration:2,ease:"bounce.out"})どんなeaseが使えるか調べる
Ease Visualizer でどのようなeaseがつかえるか調べることができます。
Ease Visualizerのグラフの見方は「急な坂は速い」「なだらかな坂はゆっくり」です。

緩急をつけない
デフォルトのeaseは “power1.out”(動きがゆっくりになって止まる)なので、 緩急つけない場合は ease:"none" と指定します。
inとoutとinOut
すべてのイージングにはbounce.in bounce.out bounce.inOut のようにin / out / inOut のパターンがあります。
- in:はじめがゆっくり
- out:終わりがゆっくり
- inOut:はじめと終わりがゆっくり
ユーザーのアクションに反応して動かすときは、out(終わりがゆっくり)を選ぶと自然なことが多いです。
(はじめがゆっくりのパターンは、ユーザーのアクションからしばらくのあいだ反応が無いように見えて変なため)
複数の要素をひとつのTweenで動かす(同時に動かす)
以下のように同じclass名の要素が複数あるとき
<svg class="star"></svg>
<svg class="star"></svg>
<svg class="star"></svg>Tweenのターゲットをclass名で指定すると、すべての要素が同時に動きます。
gsap.to(".star",{fill:"yellow", duration:3}};複数の要素をひとつのTweenで動かす(順番に動かす:stagger)
同じ状況でstagger:1 を指定すると、Tweenが1秒ずつずらして再生されるようになります。
※staggerは「〔出来事などを重ならないよう〕調整する、シフトさせる」という意味。
gsap.to(".star",{fill:"yellow", duration:3, stagger:1}};上記の例では
- ひとつめの.starが3秒かけて黄色になる
- ひとつめの再生開始の1秒後にふたつめの .starが同様にアニメーション
- ふたつめの再生開始の1秒後に3つめが同様にアニメーション
のように、開始タイミングを少しずらして襦袢に再生されていく。

※Staggerにはより細かい設定が色々あるのですがいったん説明は割愛
繰り返し再生を設定する(repeatとyoyo)
- repeat:繰り返し回数指定(1だと2回再生)
- yoyo:再生と逆再生を繰り返すようにする
繰り返し再生する場合、再生と逆再生を繰り返すとアニメーションが滑らかにつながるため、repeatとyoyoは同時に使うことが多いです。
gsap.to(".star", {color:"blue", scale:1, duration:3, repeat:1, yoyo:true})上記の例では、repeat:1 なので2回再生しますが、同時にyoyo:true になっているので2回目は逆再生になります。
つまり「元の状態から指定の状態にアニメーション、そのあと元の状態にアニメーション」という動作です。

クリックしたら再生する
なにかのイベント(クリックなど)のタイミングでTweenを動かすには、まずは変数/定数にTweenを入れます。
このときpaused:true を設定しておくことで、定義した時点ではアニメーションが再生されないようにします。
const tween = gsap.to(".star", {color:"blue", scale:1, duration:3, paused:true})そして、クリックしたときそのTweenに対して.play() を実行することで「クリックしたら再生」が実現できます。
document.querySelector("#play").addEventListener("click",function(){
  tween.play();
})※ .play() のほかに .pause() .reverse() .restart() などができます。
Timelineでできること
各Tween再生開始位置の制御(positionパラメーター)
特に設定をしない場合は、Timelineは登録したTweenを順番に再生していきます。

しかし、アニメーションの内容によっては、前のTweenと同時に再生したり、前のTweenの再生後に少し待ってから再生したり、変化を付けたい場合も多くあります。
開始位置を遅らせる”+=1″
Timelineに登録したTweenのvarsオブジェクトの後に、positionパラメーターで"+=1" と設定すると
「ひとつ前のTweenの再生終了後、1秒待ってから再生開始」という意味になります。
gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2},"+=1")
  .from(".square",{scale:0,opacity:0,duration:3})
開始位置を早める”-=0.5″
「ひとつ前のTweenの再生終了の、0.5秒前に再生開始」としたい場合は、positionパラメーターで"-=0.5" と設定します。
gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2},"-=0.5")
  .from(".square",{scale:0,opacity:0,duration:3})
ひとつ前のTweenと同時に開始”<“
「ひとつ前のTweenと同時に再生開始」と指定したい場合はpositionパラメーターで"<" と設定します。
gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2})
  .from(".square",{scale:0,opacity:0,duration:3},"<")
ひとつ前のTweenの開始1秒後に開始”<1″
「ひとつ前のTweenが開始した後、1秒まってから再生開始」の場合はpositionパラメーターで"<1" と設定します。
gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2})
  .from(".square",{scale:0,opacity:0,duration:3},"<1")
絶対値で指定
たとえば全部0秒目に再生開始したいなど、再生開始タイミングを秒数で指定したい場合は絶対値指定も利用できます。
※ただし、内容によっては特定のTweenに変更があった場合に全体的に破綻することもあるため注意が必要
gsap.timeline()
  .from(".star",{opacity:0,duration:1})
  .from(".circle",{opacity:0,duration:2},0)//0秒で開始
  .from(".square",{scale:0,opacity:0,duration:3},0)//0秒で開始タイムラインの途中にラベルをつける
サイトのオープニングアニメーションのように長いアニメーションを作成した場合に「終了直前のTweenまでスキップする」というような動作を実装したい場合がある。

そのような時は .add("好きな名前") でラベルを追加することができる。
追加したラベルの位置には .play("ラベル名") で移動できる。
const tl = gsap.timeline()
  .to(".star", { scale: 3, duration: 3 })
  .to(".star", { scale: 1, color: "blue", duration: 3 })
  .add("skipLabel")//ラベル追加
  .to(".star", { yPercent: -100, duration: 3 });
document.querySelector("#skip").addEventListener("click", () => {
  tl.play("skipLabel");//skipLabelの位置までスキップ
});Timelineの途中でスライドショーの発火などGSAP以外の何かを動かしたい
Timelineの途中でスライドショーの再生開始など、なにかGSAPとは別のものを動かしたい場合は .call() で別の関数を呼び出せる。
「オープニングアニメーションの再生終了直前に、メインビジュアルのスライドショーの再生を開始する」ような場合に便利。
const tl = gsap.timeline()
  .to(".star", { scale: 3, duration: 3 })
  .to(".star", { scale: 1, color: "blue", duration: 3 })
  .call(sliderFunc)
  .to(".star", { yPercent: -100, duration: 3 });
const sliderFunc = () =>{
 //動かしたい内容
}ScrollTriggerでできること
スクロール位置に応じてアニメーションを進捗させる(scrub)
scrub を設定すると、トリガー要素がトリガー領域内に入ったタイミングを進捗0%、トリガー領域外に出るタイミングを進捗100%となるように、スクロール位置に合わせてアニメーションを進行させます。

const myTimeline = gsap.timeline();//省略
const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",
    animation: myTimeline,
    scrub:1,//trueや0.5等でもOK。スクロール時の慣性が変わる。
    markers:true,
})scrubとあわせて、アニメーション再生完了まで要素を画面内にとどめておく(pin)
scrubのみの設定だと、設定によってはアニメーション完了時点で要素の大半が画面外に出てしまいます。
※上記のscrubについての図を参照。「トリガー要素がトリガー領域外に出る」ことが、たいていの場合画面外に出ることを指すためです。
pin:true を追加することで、アニメーションの完了まで要素が固定されるように実装できます。

const myTimeline = gsap.timeline();//省略
const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",
    animation: myTimeline,
    scrub:1,
    pin:true,
    markers:true,
})スクロール距離を要素ではなく固定値で設定する

const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",
    start: 'top top',//trigger要素の上端が、画面の上端に来たら
    end: '+=500', //任意のスクロール量
    animation: myTimeline,
    scrub:1,
    pin:true,
    markers:true,
})トリガー開始位置は要素A、終了位置は要素Bで設定する
通常の設定方法
const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",
    start:"top 80%",//trigger要素の上端が、画面の上から80%の位置にきたら
    end:"bottom 20%",//trigger要素の下端が、画面の上から80%の位置に来たら
    animation: myTimeline,
    scrub:1,
    pin:true,
    markers:true,
})
終了のトリガーを別要素にする
const myScrollTrigger = ScrollTrigger.create({
    trigger:".hoge",
    endTrigger: ".fuga",
    start:"top 80%",//trigger要素の上端が、画面の上から80%の位置にきたら
    end:"bottom 20%",//endTrigger要素の下端が、画面の上から80%の位置に来たら
    animation: myTimeline,
    scrub:1,
    pin:true,
    markers:true,
})
【書きかけ】スクロールの向きによって何が起こるかを変える
toggleActions
onEnter(), onEnterBack(), onLeave(), onLeaveBack
トラブルシューティング
easeやdurationがいうことをきかない
Tweenに指定したeaseやdurationがいうことをきかないときは、CSSで transition をかけていないか確認しましょう。
gsapと一緒にCSSのtransition が効いてしまって動作がヘンテコになります。
コメント