[Gatsbyで構築]Framer-Motionでスクロールでopacityを変更する
2022.11.10更新
Framer-Motionを使って動的にopacityを変える方法です。
最初は勘違いをしていてなかなかスクロールが反映されないなあと悩んでたけど、超凡ミスをしていただけでした。
実は超簡単に実装できました。
importするもの
import { motion, useViewportScroll, useTransform } from 'framer-motion'
実装
const IndexPage = () => { const { scrollYProgress } = useViewportScroll() const opacity = useTransform(scrollYProgress, [0, 1], [1, -5]) return () }
これだけでスクロール量に伴い色が薄くなっていきます。
簡単な説明
useViewportScroll()
本家の解説
スクロールすると値がアップデートされます。
scrollY | 縦スクロールの移動量(単位:pixels) |
scrollX | 横スクロールの移動量(単位:pixels) |
scrollYProgress | コンテンツに対する縦スクロールの移動割合(0 ~ 1) |
scrollXProgress | コンテンツに対する横スクロールの移動割合(0 ~ 1) |
useTransform
本家の解説
二通りの使い方があります。
関数を使う場合
const x = useMotionValue(5) const y = useTransform(x, res=> res + 10) console.log('y:', y.get()) // y: 15
useMotionValueとはMotionValueを明示的に使うものです。MotionValueとは、motionコンポーネントが内部的に使用するもので、アニメーション値の状態と速度を追跡するのにつかわれます。
(上記例を試すには、useMotionValueをimportする必要があります。)
motionコンポーネントに値を渡すときは「x」と「y」をそのまま使えますが、それ以外で使う場合(例えばconsole.logでコンソールに表示する場合)にはget()をつける必要があります。
マッピングを使う場合
const src = useMotionValue(0) const rangeFrom = [-10, -5, 5, 10] const rangeTo = [0, 1, 1, 0] const res= useTransform(src, rangeFrom , rangeTo) console.log('res:', res.get()) // res: 1
rangeFromとrangeToが対になっています。srcの値によってresに入る値が変化する様子は以下の通りです。
src | res |
-10以下 | 0 |
-10 ~ -5 | 0 ~ 1 |
-5 ~ 5 | 1 |
5 ~ 10 | 1 ~ 0 |
10以上 | 0 |
というようになります。
srcが-6の時はresが0.8、srcが7の時はresが0.6という感じに値は変化します。
(数値を変更して試す場合は、ブラウザでリロードをしないとコンソールには反映されません。)
また、色の指定もできます。本家の解説を見たことがあるのですが見つからないのでこんな感じという例です。
const src = useMotionValue(0) const rangeFrom = [-10, -5, 5, 10] const rangeTo = ["#fff", "#f0f", "#ff0", "#0ff"] const res= useTransform(src, rangeFrom , rangeTo) console.log('res:', res.get()) // rgba(198, 255, 161, 1)
こんなことができます。お察しの通り、#fff ~ #f0f等の「間」は滑らかに色が変わるので、useViewportScroll()と組み合わせるとスクロールで滑らかにグラデーションさせることもできます。
感想
簡単にできました。