PR
【Gatsby製ブログ】framer-motionでスクロールしたらフワッと表示させる
Reactでアニメーションをつけるときにオススメのライブラリーがframer-motionです。
もちろんReactベースのGatsbyでも使うことができます。
私のGatsbyブログでもframer-motionでアニメーションをつけています。
framer-motionは自由度が高く、色々できる代わりに使い方が結構複雑ですので、丁寧に説明していきたいと思います。
今回はframer-motionの応用、スクロールアニメーションについて説明していきます!
framer-motionでスクロールアニメーション…の前に
スルロールアニメションを作る前に、少しHooksの説明をしておきます。
framer-motionの基本とReactのHooksの話が出てきますので、こちらも合わせて読んでいただければ、と思います。
今回はその他にuseAnimationとuseInViewというHooksを使います。
useAnimation
useAnimationはアニメーションの制御をするHooksです。
こちらで説明した「ラジオボタンを選んだときにその色に変わる」というアニメーションもuseAnimationを使って書くことができます。
import { motion, useAnimation } from "framer-motion" //useAnimationをframer-motionからインポートする
…
- const [color, setColor] = useState("red"); //このuseStateは必要なし
+ const control = useAnimation(); //代わりにuseAnimationでアニメーションのコントロールをする
- const colorChange = (e) => {setColor(e.target.value)} ;
+ const colorChange = (e) => {control.start(e.target.value)} ;
//さっき定義したuseAnimationを「.start("アニメーション先")」でアニメーションスタートさせる。
//"アニメーション先"はvariantsでの状態名を指定もいいし、直接状態を定義してもOK。
const changeColorVariants = { //状態を3つ(red、blue、green)Variantsで準備しておく。
red: {
color: "white",
backgroundColor: "#ff0000",
transition: {
duration: 2,
}
},
blue: {
color: "white",
backgroundColor: "#0080ff",
transition: {
duration: 2,
}
},
green: {
color: "white",
backgroundColor: "#00fa9a",
transition: {
duration: 2,
}
}
}
return (
…
<motion.div
variants = {changeColorVariants}
initial = "red"
- animate = {color}
+ animate = {control} //animateには定義したuseAnimationのコントロールを指定
style={{fontSize:"3rem", width: 600, height: 200, textAlign: "center", lineHeight: "200px" }}
>
Variantsのテストだよ
</motion.div>
<input type = "radio" name ="colorselect" value = "red" onChange = {colorChange} }/><label>赤</label>
<input type = "radio" name ="colorselect" value = "blue" onChange = {colorChange} }/><label>青</label>
<input type = "radio" name ="colorselect" value = "green" onChange = {colorChange} /><label>緑</label>
…
)
useStateをかませる必要がなく「.start(“アニメーション先”)」でシンプルにアニメーション発火ができるのでわかりやすいです。
今回はこれをuseEffectに入れておきます。
useInView
useInViewは要素が画面内に入ったかどうか判定するHooksです。
まずは、react-intersection-observerをインストールします。
$ yarn add react-intersection-observer
そして、react-intersection-observerからuseInViewをインポートしておいて、次のように使います。
import { useInView } from 'react-intersection-observer' //useInViewをreact-intersection-observerからインポート
…
const [ref, inView] = useInView();
…
<div ref={ref}>この要素が入ったらinViewがtrueになるよ。</div>
これ単体でアレコレ言っても面白くないので、実際にスクロールアニメーションを作りながら説明します。
framer-motionでスクロールアニメーションを作る
それでは、framer-motionを使ってスクロールアニメーションを作っていきましょう!
早速ですが、コードを見てみましょう。
import React, { useEffect } from "react";
import Layout from "../components/layout";
import { motion, useAnimation } from "framer-motion";
import { useInView } from "react-intersection-observer";
const ScrollAnimationTest = ({ data, location }) => {
const control = useAnimation(); //useAnimationを使ってコントローラーを作っておく。
const [ref, isInView] = useInView({triggerOnce: true});
//↑useInView。refで参照している要素が画面内に入ったらisInViewがtrueになる
const scrollVariants = {
visible: {
y: 0,
opacity: 1,
transition: {
//duration(アニメーションの長さ)とdelay(アニメーションを遅らせる)をイイカンジに設定する。
//そうしないとスクロールアニメーションっぽくない。
duration: 1,
delay: 0.8,
type: "spring",
},
},
hidden: {
y: 30,
opacity: 0,
},
}
useEffect( //useEffectを使って、要素が画面内に入ったらcontrolをvisibleにする
()=>{
if(isInView){
control.start("visible");
}
},
[isInView]
);
return (
<Layout location={location} title="Scroll Animation Test" >
<div style={{fontSize: "5rem", height: "150vh"}}>
あれは…なんだ!?
</div>
<motion.div
style={{fontSize: "8rem", height: "50vh"}}
ref = {ref} //refで、useInViewでこの要素を参照するようにする。
variants = {scrollVariants}
initial = "hidden"
animate = {control} //animateはcontrolを指定。これでcontrolの状態にアニメーションしていく
>
クマだ!!クマが出たぞ!
</motion.div>
</Layout>
)
}
export default ScrollAnimationTest
これだけで、簡単にスクロールアニメーションを実装することができました!
とはいえ、useAnimation、useInViewとuseEffectがからみ合ってるので、Hooksに慣れてないと最初はわかりにくいかもしれません…。
useInViewは
const [ref, isInView] = useInView({triggerOnce: true});
とすることで、要素が画面に入ったかどうか一度だけ判定します。その後、画面から外れてもisInViewはtrueになったままですのでアニメーションは一度だけ発火する、ということになります。
ですが、今回は、
const [ref, isInView] = useInView();
としていても、アニメーションとしては一度だけしか発火しません。
これだと、確かに要素が画面内に入ればisInViewはtrue、外れればfalseになります。
ですが、falseになったときのcontrolの値変更の処理を書いていないので、一度control.start(“visible”)になってしまえば”hidden”に戻らないからです。
framer-motionでスクロールアニメーション(ちょっと応用)
ということで、先ほどのコードを少しいじって、要素が画面外に外れてもう一度入ったら、再びアニメーションが発火するようにしてみましょう。
さっきのメモ部分がわかっていれば、すぐにやり方はイメージできるはずです!変更箇所だけ載せておきます。
…
- const [ref, isInView] = useInView({triggerOnce: true});
+ const [ref, isInView] = useInView(); //triggerOnceを外して、何度でも判定をするようにする。
…
useEffect(
()=>{
if(isInView){
control.start("visible");
}
+ if(!isInView){ //画面外に外れた際のcontrolを"hidden"にする処理を追加
+ control.start("hidden");
+ }
},
[isInView]
);
…
何度もアニメーションを発火させたいときは、このようにisInViewがfalseになったときの処理を追加しましょう。
まとめ
スクロールアニメーションを実装するだけで、かなりサイトがリッチに見えます。
手軽な上に実用的ですので、アニメーションの手始めにいかがでしょうか?
最近本格的にCSSの勉強を始めました。
WordPressでもGatsbyJSでも必要な基本的な知識「CSS」…これが奥深い。
もちろんCSSに関する基本的な知識はあるのですが、引き出しは多くしておきたいものです。
ワンランク上のホームページ、ブログ作成を目指して、特に「これはよかった」というオススメのCSS学習教材の紹介をしていきます。
動画編
Webデザインのオンラインスクールなどは沢山ありますが、数万円〜数十万円するので、なかなかハードルが高いですよね。
そこでオススメなのはUdemy。
このブログでもちょくちょく紹介させてもらっていますが、一つの講座買い切り、というのがありがたいです。
しかも、種類もかなり豊富!GatsbyJSの講座まである、というのは他ではなかなかないです。
そのなかでもオススメのCSSに関する講座を紹介しておきます。
CSSの講座とかは沢山あるので、「これよさそう!」と思ったものを探すのも楽しいかもしれません。
書籍編
CSSを実践的に書いていくなら、書籍も便利です。
本を片手にコーディング、というのは効率もいいですよね。
こちらもオススメの本を紹介しておきます。
CSSの基本ができている人が「次のステップに行きたいなぁ…」というときにオススメです。