いわゆるガチャガチャ動かしたいという要望のホームページ制作(非 React)で初めて GSAP というアニメーションライブラリを使ってる。 できることがありすぎて、まだ理解しきれてないが今回は ScrollTrigger を使って CSS のクラスを変更しアニメーションを発火させた後に、アニメーション終了を持ってコールバックを実行したかったのメモ
ライブラリ選定のメモ
パララックス・アニメーションライブラリで比較をした
aos vs gsap vs scrollmagic vs t-scroll vs velocityjs vs waypoints vs wowjs | npm trends
多くのライブラリが DT であまりメンテされておらず、ほぼ唯一 GSAP が TypeScript 化されており比較的メンテナンスがされていたので選定した
JavaScript に Intersection information があるので、ある程度のことはこれで実装可能だし、昨今の Web アプリケーションではガチャガチャ動くのはあまり意味をなさない装飾なのでこの分野の需要が減少しているのかも知れない。といっても広告的な "ほうむぺーじ" ではまだまだ必要とされる分野だとも思う (jQueryだってめちゃくちゃ使われてるし)
ScrollTrigger を使ってクラス名を変更し CSS アニメーションを設定する
シンプルな CSS アニメーションを作成する
.js-fadeUp { opacity: 0; transform: translateY(20px); transition: all 0.6s ease-in-out; } .js-fadeUp.fade-in { opacity: 1; transform: translateY(0); }
.js-fadeup
クラスがある要素をターゲットに、.fade-in
クラスが付けられるとアニメーションが開始される想定
GSAP でクラス名を変更する
import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; // registerPlugin しないとエラーになる gsap.registerPlugin(ScrollTrigger); const targets = document.querySelectorAll('.js-fadeUp'); targets.forEach((target, index) => { ScrollTrigger.create({ trigger: target, id: `fadeUpContent-${index + 1}`, start: 'top-=100 center', end: 'bottom top', toggleClass: { targets: target, className: 'fade-in' }, once: true, }); });
これで .js-fadeup
クラスのある要素がスクロールに応じてフェードインするようになった!
📝 note.
once
: Boolean - Iftrue
, the ScrollTrigger will kill() itself as soon as the end position is reached once. This causes it to stop listening for scroll events and it becomes eligible for garbage collection. This will only call onEnter a maximum of one time as well. It does not kill the associated animation. It's perfect for times when you only want an animation to play once when scrolling forward and never get reset or replayed. It also sets the toggleActions to "play none none none".
cf. ScrollTrigger | GSAP | Docs & Learning
once
を付けておくと一度だけ発火し、kill()
されメモリを開放してくれるトノコト。
こってりとしたアニメーションを何度も見せられるのは、あまりユーザー体験が良いとは思わないので once
を設定することにした。
CSS アニメーションが完了したらコールバックで対象要素を操作したい
アニメーション完了時に CSS のクラス名を変更するなど、アニメーション完了のコールバックで要素を操作したい
ScrollTrigger: onComplete callback - GSAP - GreenSock このスレッドには refresh
イベントリスナーを使えば良いと回答されていたがうまく動作せず、scrollEnd
を使ってみたが、アニメーションが発火した要素ごとにイベントが発火するものでは無さそうだった。
cf. static-addEventListener | GSAP | Docs & Learning
onEnter, onLeave コールバックを使えば、対象ごとにコールバックを設定できる
onEnter
: Function - A callback for when the scroll position moves forward past the "start" (typically when the trigger is scrolled into view). It receives one parameteronLeave
: Function - A callback for when the scroll position moves forward past the "end" (typically when the trigger is scrolled out of view). It receives one parameter
cf. static-addEventListener | GSAP | Docs & Learning
CSS アニメーションの時間を測って即コールバックをするなら onEnter
を使いコールバック内で setTimeout
で CSS アニメーションの時間分待てば良さそう
厳密さがあまり必要でないなら、onLeave
を使う方が無駄にタイマーを使わずに済むので効率的だと思う
import gsap from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); const targets = document.querySelectorAll('.js-fadeUp'); targets.forEach((target, index) => { ScrollTrigger.create({ trigger: target, id: `fadeUpContent-${index + 1}`, start: 'top-=100 center', end: 'bottom top', toggleClass: { targets: target, className: 'fade-in' }, once: true, // css アニメーションを待って実行させる場合は onEnter を使う onEnter: (self) => { // self は globalThis.ScrollTrigger 型 const target = self.vars.trigger; // gsap.DOMTarget | undefined // ⚠ HTMLElement 型として扱わないと target.classList が type error になる if (!target || target instanceof HTMLElement !== true) { return; } // css animation が終わるまで待つ window.setTimeout(() => { target.classList.add('fade-in-complete'); }, 600); }, // css アニメーションを特に考慮しないなら onLeave で十分 onLeave: (self) => { const target = self.vars.trigger; if (!target || target instanceof HTMLElement !== true) { return; } target.classList.add('leaved'); } }); });
ポイントとしては self.vars.trigger
で取得できる、アニメーションのターゲット要素が gsap.DOMTarget | undefined
型なので classList
などを使いたい場合は target instanceof HTMLElement
で type guard してあげる必要がある部分
Sample
See the Pen GSAP CSS animation callback by KIKIKI (@kikiki_kiki) on CodePen.
⚠ onLeave
はスクロールの高さが足りないと発火しない場合がある
なんとなくな理解だけど、GSAP の ScrollTrigger を使って CSS アニメーション発火した後にコールバックで処理ができるようになった!
おわり
[参考]
- aos vs gsap vs scrollmagic vs t-scroll vs velocityjs vs waypoints vs wowjs | npm trends
- Homepage | GSAP
- GitHub - greensock/GSAP: GSAP (GreenSock Animation Platform), a JavaScript animation library for the modern web
- GSAP | Docs & Learning
- 【2021年最新】GSAPの「ScrollTrigger」を使って爆速でスクロールアニメを実装する - to-R Media
- GSAPのScrollTriggerを使用してスクロールアニメーションを実装してみた - Onesite
- GSAPを使って複雑なオープニングアニメーションを作ってみよう | 東京のホームページ制作 / WEB制作会社 BRISK
- 【GSAP】スクロールでふわっとフェードインさせる方法【アニメーションのサンプルあり】 - じゅんぺいブログ
- 交差オブザーバー API - Web API | MDN
- JSでのスクロール連動エフェクトにはIntersection Observerが便利 - ICS MEDIA
- <easing-function> - CSS: カスケーディングスタイルシート | MDN