はじめに
簡単に優れたUIのコンポーネントを作成することができるということでコンポーネントライブラリを用いることがよくあります。そんなコンポーネントライブラリのうちChakra UIを導入するときに必要になったFramer Motionというライブラリについて解説します。
この記事はReactについての知識があれば読み進める内容となっています。Chakra UIは使用しません。
Framer Motion
Framer MotionはReact用のアニメーションのライブラリです。シンプルかつ強固に宣言的な記法ができます。宣言的な面がReactの思想とも合っていて使い心地が非常に良いライブラリとなっています。
上記の実装のために必要なコードはこれだけです。タップしたりホバーした時に設定したアニメーションが動作します。
<motion.div
whileHover={{ scale: 1.2, rotate: 90 }}
whileTap={{
scale: 0.8,
rotate: -90,
borderRadius: "100%"
}}
/>
利用方法
パッケージは以下のようにインストールして利用します。
npm i framer-motion
pnpm add framer-motion
基本的な使い方
Framer Motionはモーションコンポーネントを主としたライブラリです。このコンポーネントはFramer Motionによるアニメーション機能が備わったHTML要素のように扱えます。
例えば<motion.div />
は、<div>
にFramer Motionによるアニメーション機能が備わったと考えて操作することが出来ます。
import { motion } from 'framer-motion';
const SampleMotion = (): JSX.Element => (
<motion.div />
);
基本のアニメーション
Framer Motionによるアニメーション機能はanimate
に値を設定して付与することが出来ます。
例えばanimate
に以下のように設定されているとします
<motion.div animate={{ x: 0 }} />
その後、何らかのきっかけで以下のようになった場合はこのコンポーネントが横軸に100px移動するアニメーションが画面に表示されます。
<motion.div animate={{ x: 100 }} />
アニメーションの振る舞いはtransition
で細かく定義することが出来ます。
例えば単振動のように振る舞うをするアニメーションは以下のように作れます。
<motion.div animate={{ x: 100 }} transition={{ type: 'spring', damping: 0 }} />
type: 'spring'
でバネのように動くように指定して、damping: 0
で減衰を0に設定しています。
設定できる他の値についてはこちらを参照してください。
ジェスチャー
ホバーやタップ、ドラッグなどのユーザーの動作に合わせたアニメーションを設定することが出来ます。
ホバーはwhileHover
で、タップはwhileTap
のようにwhile+動作
に値を設定してモーションコンポーネントにその動作に合わせたアニメーションを付与します。
ホバーした時にサイズを4倍にするようなアニメーションは以下のように書きます(サイズのスケールは一次元の倍率なので2に設定します)。
<motion.div whileHover={{ scale: 2 }} />
whileHover
などに渡せる設定値はanimate
に渡せる値と同じです。
スクロール
スクロールに関するアニメーションはスクロールに連動したものと画面(ビューポート)に要素が現れると発生するものの二種類があります。
スクロールに連動したアニメーションはuseScroll
を用いて作成します。useScroll
はピクセル単位のスクロールの絶対的な位置を表すscrollX
とscrollY
と0~1で定義されたスクロール位置を返すscrollXProgress
とscrollYProgress
の4つの値をオブジェクトとして返します。
const { scrollYProgress } = useScroll();
return (
<motion.div style={{ scaleX: scrollYProgress }} />
);
これらの返り値はReactで管理された状態ではないので、変化しても再レンダリングは起きません。そのためuseEffect
やuseMemo
などの第二引数の一部として渡したとしても想定通りの動作をしません。そのため、変化した時に何らかの処理を実行したり変化を監視したい場合はuseMotionValueEvent
を用いる必要が有ります。例えば、縦軸のスクロールの進捗が変わるたびに実行したい場合は以下のように書けます。
const { scrollYProgress } = useScroll();
useMotionValueEvent(scrollYProgress, "change", (latest) => {
console.log(latest);
});
また、useScroll
の返り値はuseSpring
というhooksを用いてバネのような増加方法を実現することもできます。
const { scrollYProgress } = useScroll();
const scaleX = useSpring(scrollYProgress);
return <motion.div style={{ scaleX }} />;
続いてスクロールによって起きるアニメーションです。このアニメーションはwhereInView
を用いて行います。初期条件が必要だったらinitial
を用いて設定します。
<motion.div
initial={{ opacity: 0 }}
whereInView={{ opacity: 1 }}
/>
ジェスチャーに似ていますが、スクロールという動作と考えると妥当ですね。このアニメーションはviewport
で詳細を設定することが出来ます。基本的にはモーションコンポーネントが画面内に入った時に指定したアニメーションが動作しますが、指定したコンポーネント内に現れた時にアニメーションを動かすためにはviewport
内のroot
を設定する必要があります。
const scrollRef = useRef(null)
return (
<div ref={scrollRef} style={{ overflow: "scroll" }}>
<motion.div
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ root: scrollRef }}
/>
</div>
);
さいごに
Framer Motionについて、基本的な使い方を紹介しました。これまでCSSを用いたアニメーションは苦手としていましたが、このライブラリを用いて作成するのは楽しくできそうだなという印象を持ちました。
このライブラリはかなり豊富な機能があり全てを紹介しきれませんでしたが、他の機能もとても使いやすいのでドキュメントなどを参照しつつ利用してみてはいかがでしょうか。