GreenSockを使用したReactコンポーネントのアニメーション
公開: 2022-03-10ワールドワイドウェブの初期の頃、物事はかなり静的で退屈でした。 ウェブページは主に、印刷の世界からアニメーションが導入されるまでのグラフィックデザインとレイアウトに基づいていました。 アニメーションは、静的なWebページよりも長く人々の注意を引き付け、保持することができ、アイデアや概念をより明確かつ効果的に伝達します。
ただし、正しく行われないと、アニメーションがユーザーの製品との対話を妨げ、トラクションに悪影響を与える可能性があります。 GreenSock Animation Platform AKA(GSAP)は、フロントエンドの開発者、アニメーター、デザイナーがパフォーマンスの高いタイムラインベースのアニメーションを作成できるようにする強力なJavaScriptライブラリです。 これにより、アニメーション愛好家は、CSSが提供するkeyframe
やanimation
のプロパティを制限することなく、アニメーションシーケンスを正確に制御できます。
この記事では、 scrollTriggers
、 Timelines
、 Easing
などのGSAPのいくつかの機能を紹介し、最後に、この機能を使用してReactアプリをアニメーション化することで直感的なユーザーインターフェイスを構築します。 codesandboxで完成したプロジェクトをチェックしてください。
この記事は、次の場合に役立ちます。
- HTML、CSS、およびJavaScriptを使用してWebアプリケーションでアニメーションを作成しています。
- すでにanimate.css、React-motion、Framer-motion、React-Springなどのパッケージを使用してReactアプリでアニメーション化されたウェブページを構築しており、さらに代替案を確認したいと考えています。
- あなたはReactの愛好家であり、ReactベースのWebアプリケーションで複雑なアニメーションを作成したいと考えています。
既存のWebプロジェクトからさまざまなアニメーションを作成する方法を見ていきます。 それを手に入れよう!
注:この記事は、HTML、CSS、JavaScript、およびReact.jsに慣れていることを前提としています。
GSAPとは何ですか?
GreenSock Animation PlatformはGSAPとも呼ばれ、開発者がモジュール式で宣言型の再利用可能な方法でアプリをアニメーション化できる、最新のWeb向けの超高性能のプロフェッショナルグレードのアニメーションです。 フレームワークに依存せず、JavaScriptベースのプロジェクト全体で使用できます。バンドルサイズは非常に小さく、アプリを肥大化させることはありません。
GSAPは、WebGLエクスペリエンスの作成に使用されるキャンバスアニメーションを実行し、動的なSVGアニメーションを作成することができます。
なぜGSAPを使用するのですか?
たぶん、あなたはまだ他のフレームワークを裏切る準備ができていないか、GSAPに付属している優れた機能を受け入れることを確信していません。 GSAPを検討する理由をいくつか挙げさせてください。
複雑なアニメーションを作成できます
GSAP JavaScriptライブラリを使用すると、開発者はこれらのサイトの場合のように、単純なものから非常に複雑な物理ベースのアニメーションを作成できます。これにより、開発者と設計者はモーションをシーケンスし、アニメーションを動的に制御できます。 DrawSVGPlugin、MorphSVGPluginなどのプラグインがたくさんあり、SVGベースのアニメーションや2D / 3Dアニメーションの作成を現実のものにします。 DOM要素にGSAPを統合するだけでなく、WebGL / Canvas /Three.jsコンテキストベースのアニメーション内でそれらを使用できます。
さらに、GSAPのイージング機能は非常に洗練されているため、通常のCSSアニメーションと比較して、複数のベジエで高度な効果を作成できます。
パフォーマンス
GSAPは、さまざまなブラウザで優れたパフォーマンスを発揮します。
GSAPのチームによると、彼らのWebサイトでは、「GSAPはjQueryよりも20倍高速であり、さらにGSAPは地球上で最速のフル機能のスクリプトアニメーションツールです。 多くの場合、CSS3アニメーションやトランジションよりもさらに高速です。」 速度比較を自分で確認してください。
さらに、GSAPアニメーションは、デスクトップコンピューター、タブレット、スマートフォンの両方で簡単に実行できます。 プレフィックスの長いリストを追加する必要はありません。これはすべて、GSAPによって内部的に処理されています。
GSAPのその他のメリットを確認するか、SarahDrasnerがそれについて何を言っているかをここで確認できます。
GSAPの短所
すべてのプロジェクトで常にGSAPを使用する必要があると言っていますか? もちろん違います! GSAPを使用したくない理由は1つだけだと思います。 確認してみましょう!
- GSAPはJavaScriptベースのアニメーションライブラリにすぎないため、メソッドとAPIを効果的に利用するには、JavaScriptとDOMの操作に関するある程度の知識が必要です。 この学習曲線の欠点は、JavaScriptを使い始めた初心者にとって、さらに複雑になる余地を残します。
- GSAPはCSSベースのアニメーションに対応していないため、そのようなライブラリを探している場合は、CSSアニメーションで
keyframes
を使用することをお勧めします。
他に理由がある場合は、コメントセクションでお気軽に共有してください。
さて、あなたの疑問が解消されたので、GSAPのいくつかの核心に飛びつきましょう。
GSAPの基本
Reactを使用してアニメーションを作成する前に、GSAPのいくつかのメソッドとビルディングブロックについて理解しましょう。
GSAPの基本をすでに知っている場合は、このセクションをスキップしてプロジェクトセクションに直接ジャンプできます。ここで、スクロール中にランディングページを歪めます。
トゥイーン
トゥイーンは、アニメーションの1つの動きです。 GSAPでは、トゥイーンの構文は次のとおりです。
TweenMax.method(element, duration, vars)
この構文が何を表すかを見てみましょう。
-
method
とは、トゥイーンしたいGSAPメソッドを指します。 -
element
は、アニメーション化する要素です。 複数の要素のトゥイーンを同時に作成する場合は、要素の配列をelement
に渡すことができます。 -
duration
は、トゥイーンの期間です。 これは秒単位の整数です(s
サフィックスなし!)。 -
vars
は、アニメートするプロパティのオブジェクトです。 これについては後で詳しく説明します。
GSAPメソッド
GSAPは、アニメーションを作成するための多数のメソッドを提供します。 この記事では、 gsap.to
、 gsap.from
、 gsap.fromTo
などのいくつかについてのみ言及します。 あなたは彼らのドキュメントで他のクールな方法をチェックすることができます。 このセクションで説明する方法は、このチュートリアルの後半でプロジェクトを構築する際に使用されます。
-
gsap.to()
オブジェクトをアニメーション化する必要のある値、つまりアニメーション化されたオブジェクトの終了プロパティ値—以下に示すように:gsap.to('.ball', {x:250, duration: 5})
to
メソッドを示すために、以下のcodepenデモは、ボール250px
のクラスを持つ要素が、コンポーネントがマウントされるときに5秒でx-axis
を横切って移動することを示しています。 期間が指定されていない場合、デフォルトの500ミリ秒が使用されます。
注: x
軸とy-axis
軸はそれぞれ水平軸と垂直軸を表し、 translateX
やtranslateY
などのCSS変換プロパティでも、 pixel-measured
はx
とy
として、パーセンテージベースの変換の場合はxPercent
とyPercent
として表されます。
コードの完全なスニペットを表示するには、codepenプレイグラウンドを確認してください。
-
gsap.from()
—オブジェクトをアニメーション化する値を定義します—つまり、アニメーションの開始値:gsap.from('.square', {duration:3, scale: 4})
3seconds
デモは、コンポーネントがマウントされたときに、 square
のクラスを持つ要素が3秒で4のスケールからどのようにサイズ変更されるかを示しています。 このcodepenで完全なコードスニペットを確認してください。
-
gsap.fromTo()
—アニメーションの開始値と終了値を定義できます。 これは、from()
)メソッドとto()
メソッドの両方の組み合わせです。
外観は次のとおりです。
gsap.fromTo('.ball',{opacity:0 }, {opacity: 1 , x: 200 , duration: 3 }); gsap.fromTo('.square', {opacity:0, x:200}, { opacity:1, x: 1 , duration: 3 });
このコードは、不透明度0からx-axis
全体の不透明度1
まで3 seconds
でball
のクラスを使用して要素をアニメーション化し、 square
のクラスはx-axis
軸全体で不透明度0
から1
まで3 seconds
でアニメーション化されます。コンポーネントがマウントされるときのみx-axis
。 fromTo
メソッドがどのように機能するかと完全なコードスニペットを確認するには、以下のCodePenのデモを確認してください。
注: left
やtop
などの位置プロパティをアニメーション化するときは常に、関連する要素がrelative
、 absolute
、またはfixed
のいずれかのCSS位置プロパティを持っていることを確認する必要があります。
緩和
GSAPの公式ドキュメントでは、Tweenのタイミングを変更する主な方法としてイージングを定義しています。 オブジェクトがさまざまなポイントでどのように位置を変更するかを決定します。 Easeは、GSAPのアニメーションの変化率を制御し、オブジェクトのアニメーションのスタイルを設定するために使用されます。
GSAPには、アニメーションの動作をより細かく制御できるように、さまざまな種類の使いやすさとオプションが用意されています。 また、好みのイーズ設定を選択するのに役立つイーズビジュアライザーも提供します。
イーズには3つのタイプがあり、操作が異なります。
-
in()
—モーションはゆっくりと開始し、アニメーションの終わりに向かってペースを上げます。 -
out()
—アニメーションは速く始まり、アニメーションの終わりに遅くなります。 -
inOut()
—アニメーションはゆっくりと始まり、途中でペースを上げ、ゆっくりと終わります。
これらのイージングの例では、3種類のbounce.in
、 bounce.out
、 bounce.inOut
を表示するトゥイーンをチェーンし、次のアニメーションを開始する前にアニメーションが完了するまでにかかる秒数の遅延を設定しました。コンポーネントはマウントです。 このパターンは繰り返されます。次のセクションでは、タイムラインを使用してこれをより適切に行う方法を説明します。
タイムライン
タイムラインは、複数のトゥイーンのコンテナとして機能します。 トゥイーンを順番にアニメートし、前のトゥイーンの継続時間には依存しません。 タイムラインを使用すると、トゥイーン全体を簡単に制御し、タイミングを正確に管理できます。
タイムラインは、次のようにタイムラインのインスタンスを作成することで記述できます。
gsap.timeline();
次のコードでは、2つの異なる方法で複数のトゥイーンをタイムラインにチェーンすることもできます。
##Method 1 const tl = gsap.timeline(); // create an instance and assign it a variable tl.add(); // add tween to timeline tl.to('element', {}); tl.from('element', {}); ##Method 2 gsap.timeline() .add() // add tween to timeline .to('element', {}) .from('element', {})
前の例をタイムラインで再現してみましょう。
const { useRef, useEffect } = React; const Balls = () => { useEffect(() => { const tl = gsap.timeline(); tl.to('#ball1', {x:1000, ease:"bounce.in", duration: 3}) tl.to('#ball2', {x:1000, ease:"bounce.out", duration: 3, delay:3 }) tl.to('#ball3', {x:1000, ease:"bounce.inOut", duration: 3, delay:6 }) }, []); } ReactDOM.render( , document.getElementById('app'));
const { useRef, useEffect } = React; const Balls = () => { useEffect(() => { const tl = gsap.timeline(); tl.to('#ball1', {x:1000, ease:"bounce.in", duration: 3}) tl.to('#ball2', {x:1000, ease:"bounce.out", duration: 3, delay:3 }) tl.to('#ball3', {x:1000, ease:"bounce.inOut", duration: 3, delay:6 }) }, []); } ReactDOM.render( , document.getElementById('app'));
useEffect
フック内で、タイムラインのインスタンスを保持する変数(tl)
を作成し、次にtl
変数を使用して、アニメーション化する前のトゥイーンに依存せずに、トゥイーンを順次アニメーション化し、前の例。 このデモの完全なコードスニペットについては、以下のcodepenプレイグラウンドを確認してください。
GSAPの基本的な構成要素のいくつかを理解したので、次のセクションで、典型的なReactアプリで完全なアニメーションを作成する方法を見てみましょう。 フライトを始めましょう!
ReactとGSAPを使用してアニメーション化されたランディングページを構築する
Reactアプリをアニメーション化してみましょう。 依存関係をインストールするために、 npm install
を開始して実行する前に、リポジトリのクローンを作成してください。
私たちは何を構築していますか?
現在、ランディングページには、白い背景のテキストがいくつか含まれています。メニューはドロップダウンせず、実際にはアニメーションがありません。 以下は、ランディングページに追加するものです。
- ホームページのテキストとロゴをアニメーション化して、コンポーネントをマウントしたときに簡単に表示できるようにします。
- メニューをアニメーション化して、メニューをクリックするとドロップダウンするようにします。
- ページがスクロールするときに、ギャラリーページの画像を
20deg
せます。
codesandboxのデモをチェックしてください。
ランディングページのプロセスをコンポーネントに分割するので、理解しやすくなります。 プロセスは次のとおりです。
- アニメーションメソッドを定義し、
- テキストとロゴをアニメーション化、
- トグルメニュー、
- ページスクロールで画像を
20deg
せます。
コンポーネント
Animate.js
—すべてのアニメーションメソッドを定義しました。-
Image.js
—ギャレー画像をインポートします。 -
Menu.js
—メニュートグル機能が含まれています。 -
Header.js
—ナビゲーションリンクが含まれています。
アニメーションメソッドを定義する
src
ディレクトリ内にcomponent
フォルダを作成し、 animate.js
ファイルを作成します。 次のコードをコピーして貼り付けます。
import gsap from "gsap" import { ScrollTrigger } from "gsap/ScrollTrigger"; //Animate text export const textIntro = elem => { gsap.from(elem, { xPercent: -20, opacity: 0, stagger: 0.2, duration: 2, scale: -1, ease: "back", }); };
ここでは、 gsap
をインポートしました。 ランディングページのテキストをアニメーション化するエクスポートされた矢印関数を作成しました。 gsap.from()
メソッドは、オブジェクトのアニメーション化元の値を定義することに注意してください。 この関数には、アニメーション化する必要のあるクラスを表すelem
パラメーターがあります。 いくつかのプロパティを取り、 xPercent: -20
(オブジェクトを-20%変換)などの値を割り当て、オブジェクトに不透明度を与えず、オブジェクトを-1
でscale
し、オブジェクトを2sec
でease
に戻します。
これが機能するかどうかを確認するには、 App.js
にアクセスして、次のコードを含めます。
... //import textIntro import {textIntro} from "./components/Animate" ... //using useRef hook to access the textIntro DOM let intro = useRef(null) useEffect(() => { textIntro(intro) }, []) function Home() { return ( <div className='container'> <div className='wrapper'> <h5 className="intro" ref={(el) => (intro = el)}></h5> The <b>SHOPPER</b>, is a worldclass, innovative, global online ecommerce platform, that meets your everyday daily needs. </h5> </div> </div> ); }
ここでは、 Aminate
コンポーネントからtextIntro
メソッドをインポートします。 DOMにアクセスするために、以前はuseRef
を使用していました。 値がnull
に設定されている変数intro
を作成しました。 次に、 useEffect
フック内で、 textIntro
メソッドとintro
変数を呼び出しました。 ホームコンポーネント内のh5
タグで、 ref
propを定義し、 intro
変数を渡しました。
次に、メニューがありますが、クリックしてもドロップダウンしません。 それを機能させましょう! Header.js
コンポーネント内に、以下のコードを追加します。
import React, { useState, useEffect, useRef } from "react"; import { withRouter, Link, useHistory } from "react-router-dom"; import Menu from "./Menu"; const Header = () => { const history = useHistory() let logo = useRef(null); //State of our Menu const [state, setState] = useState({ initial: false, clicked: null, menuName: "Menu", }); // State of our button const [disabled, setDisabled] = useState(false); //When the component mounts useEffect(() => { textIntro(logo); //Listening for page changes. history.listen(() => { setState({ clicked: false, menuName: "Menu" }); }); }, [history]); //toggle menu const toggleMenu = () => { disableMenu(); if (state.initial === false) { setState({ initial: null, clicked: true, menuName: "Close", }); } else if (state.clicked === true) { setState({ clicked: !state.clicked, menuName: "Menu", }); } else if (state.clicked === false) { setState({ clicked: !state.clicked, menuName: "Close", }); } }; // check if out button is disabled const disableMenu = () => { setDisabled(!disabled); setTimeout(() => { setDisabled(false); }, 1200); }; return ( <header> <div className="container"> <div className="wrapper"> <div className="inner-header"> <div className="logo" ref={(el) => (logo = el)}> <Link to="/">SHOPPER.</Link> </div> <div className="menu"> <button disabled={disabled} onClick={toggleMenu}> {state.menuName} </button> </div> </div> </div> </div> <Menu state={state} /> </header> ); }; export default withRouter(Header);
このコンポーネントでは、メニューとボタンの状態を定義し、useEffectフック内で、 useEffect
フックを使用してページの変更をuseHistory
しました。ページが変更された場合は、 clicked
とmenuName
の状態値をそれぞれfalse
とMenu
に設定しました。
メニューを処理するために、初期状態の値がfalseであるかどうかを確認し、trueの場合、 initial
、 clicked
、 menuName
の値をnull
、 true
、 Close
に変更します。 それ以外の場合は、ボタンがクリックされているかどうかを確認します。trueの場合は、 menuName
をMenu
に変更します。 次に、ボタンがクリックされたときにボタンを1sec
無効にするdisabledMenu
関数があります。
最後に、 button
で、 disabled
をdisabled
に割り当てました。これは、値がtrue
場合にボタンを無効にするブール値です。 また、ボタンのonClick
ハンドラーはtoggleMenu
関数に関連付けられています。 ここで行ったのは、 menu
テキストを切り替えて、状態をMenu
コンポーネントに渡すことだけでした。これは、最も早く作成します。 実際のMenu
コンポーネントを作成する前に、メニュードロップダウンを作成するメソッドを記述しましょう。 Animate.js
にアクセスして、このコードを貼り付けます。
.... //Open menu export const menuShow = (elem1, elem2) => { gsap.from([elem1, elem2], { duration: 0.7, height: 0, transformOrigin: "right top", skewY: 2, ease: "power4.inOut", stagger: { amount: 0.2, }, }); }; //Close menu export const menuHide = (elem1, elem2) => { gsap.to([elem1, elem2], { duration: 0.8, height: 0, ease: "power4.inOut", stagger: { amount: 0.07, }, }); };
ここに、 menuShow
という関数があります。これは、メニューを水平方向に2度傾斜させ、メニューを緩和し、 2degrees
プロパティを使用しstagger
アニメーションをオフセットし、メニューをright to top
に0.7秒で変換します。同じプロパティが0.7sec
関数にもmenuHide
されます。 これらの関数を使用するには、 components
内にMenu.js
ファイルを作成し、このコードを貼り付けます。
import React, {useEffect, useRef} from 'react' import { gsap } from "gsap" import { Link } from "react-router-dom" import { menuShow, menuHide, textIntro, } from './Animate' const Menu = ({ state }) => { //create refs for our DOM elements let menuWrapper = useRef(null) let show1 = useRef(null) let show2 = useRef(null) let info = useRef(null) useEffect(() => { // If the menu is open and we click the menu button to close it. if (state.clicked === false) { // If menu is closed and we want to open it. menuHide(show2, show1); // Set menu to display none gsap.to(menuWrapper, { duration: 1, css: { display: "none" } }); } else if ( state.clicked === true || (state.clicked === true && state.initial === null) ) { // Set menu to display block gsap.to(menuWrapper, { duration: 0, css: { display: "block" } }); //Allow menu to have height of 100% gsap.to([show1, show2], { duration: 0, opacity: 1, height: "100%" }); menuShow(show1, show2); textIntro(info); } }, [state]) return ( <div ref={(el) => (menuWrapper = el)} className="hamburger-menu"> <div ref={(el) => (show1 = el)} className="menu-secondary-background-color" ></div> <div ref={(el) => (show2 = el)} className="menu-layer"> <div className="container"> <div className="wrapper"> <div className="menu-links"> <nav> <ul> <li> <Link ref={(el) => (line1 = el)} to="/about-us" > About </Link> </li> <li> <Link ref={(el) => (line2 = el)} to="/gallery" > Gallery </Link> </li> <li> <Link ref={(el) => (line3 = el)} to="/contact-us" > Contact us </Link> </li> </ul> </nav> <div ref={(el) => (info = el)} className="info"> <h3>Our Vision</h3> <p> Lorem ipsum dolor sit amet consectetur adipisicing elit.... </p> </div> </div> </div> </div> </div> </div> ); } export default Menu
Menu
コンポーネントで行ったことは、 menuShow
、 menuHide
、およびtextIntro
であるアニメーション関数をインポートすることでした。 次に、 refs
フックを使用してDOM
要素に作成された各参照に変数を割り当て、値としてnull
をuseRef
ました。 useEffect
フック内で、 menu
の状態をチェックします。 clicked
がfalse
の場合はmenuHide
関数を呼び出し、 clicked
された状態がtrueの場合はmenuShow
関数を呼び出します。 最後に、関係するDOM
要素に、 menuWrapper
、 show1
、 show2
という特定のrefs
が渡されるようにしました。 これで、メニューがアニメーション化されました。
それがどのように見えるか見てみましょう。
実装する最後のアニメーションは、ギャラリー内の画像がスクロールするときにskew
ようにすることです。 ギャラリーの様子を見てみましょう。
ギャラリーにスキューアニメーションを実装するには、 Animate.js
にアクセスして、いくつかのコードを追加しましょう。
.... //Skew gallery Images export const skewGallery = elem1 => { //register ScrollTrigger gsap.registerPlugin(ScrollTrigger); // make the right edge "stick" to the scroll bar. force3D: true improves performance gsap.set(elem1, { transformOrigin: "right center", force3D: true }); let clamp = gsap.utils.clamp(-20, 20) // don't let the skew go beyond 20 degrees. ScrollTrigger.create({ trigger: elem1, onUpdate: (self) => { const velocity = clamp(Math.round(self.getVelocity() / 300)); gsap.to(elem1, { skew: 0, skewY: velocity, ease: "power3", duration: 0.8, }); }, }); }
skewGallery
という関数を作成し、 elem1
をパラメーターとして渡し、 ScrollTrigger
を登録しました。
ScrollTriggerはGSAPのプラグインであり、ページのスクロール中に画像を歪める場合のように、スクロールベースのアニメーションをトリガーできます。
右端をスクロールバーに固定するために、 right center
の値をtransformOrigin
プロパティに渡しました。また、パフォーマンスを向上させるために、 force3D
プロパティを他のプロパティにtrueに設定しました。
スキューを計算し、 20degs
を超えないようにするclamp
変数を宣言しました。 ScrollTrigger
オブジェクト内で、 trigger
プロパティをelem1
paramに割り当てました。これは、この関数を呼び出すときにトリガーされる必要がある要素です。 onUpdate
コールバック関数があり、その中には現在の速度を計算して300
で除算するvelocity
変数があります。
最後に、他の値を設定して、現在の値から要素をアニメーション化します。 skew
を最初は0
に設定し、 skewY
を0.8
のvelocity
変数に設定します。
次に、 App.js
ファイルでこの関数を呼び出す必要があります。
.... import { skewGallery } from "./components/Animate" function Gallery() { let skewImage = useRef(null); useEffect(() => { skewGallery(skewImage) }, []); return ( <div ref={(el) => (skewImage = el)}> <Image/> </div> ) } ....
ここでは、。 skewImage
skewGalley
./components/Animate
しました。 useEffect
フック内で、 skewGallery
関数を呼び出し、 skewImage
をパラメーターとして渡しました。 最後に、 skewImage
をref
属性に渡しました。
あなたは私に同意するでしょう、それはこれまでのところとてもクールな旅でした。 これがCodeSanboxのプレビューです
この記事のサポートリポジトリはGithubで入手できます。
結論
ReactプロジェクトでGSAPの効力を調査しましたが、この記事では表面をかじっただけです。アニメーションに関しては、GSAPでできることに制限はありません。 GSAPの公式ウェブサイトでは、メソッドとプラグインを完全に理解するのに役立つ追加のヒントを提供しています。 人々がGSAPで行ったことにあなたの心を吹き飛ばすであろう多くのデモがあります。 コメントセクションでGSAPの使用経験をお聞かせください。
資力
- GSAPドキュメント、GreenSock
- 「GreenSockアニメーションプラットフォームの初心者向けガイド」、Nicholas Kramer、freeCodeCamp
- 「GreensockAnimationAPI(GSAP)を使用したアニメーションの概要」、Zell Liew