🌊

framer-motionでスクロールをリッチに

2024/08/30に公開

はじめに

framer-motionはアニメーションを簡単につけることができるライブラリです。
https://www.framer.com/motion/introduction/
使い方としてはこのようにタブの頭にmotion.を付け、プロップスに各値を渡します。

<motion.div animate={{ x: 100 }} />

基本的にinitialにアニメーションの初期位置、animateに終了位置、transitionに動き方を書きます。

<motion.div
    initial={{ y: 100, opacity: 0 }}
    animate={{ y: 0, opacity: 1 }}
    transition={{
        duration: 1,
        delay: 0.5,
        stiffness: 130 }}
/>

これだけでアニメーションができるのですごく簡単ですね。
調べてみるとスクロールでふわっと要素を表示したり、みた事あるwebアニメーションも簡単にできるみたいなので、やってみました。

作ってみた画面

コード

const cakeList = [
    {
      id: 1,
      name: "ショートケーキ",
      path: "cake1",
      discription:
        "割愛",
    },
    {
      id: 2,
      name: "チョコレートケーキ",
      path: "cake2",
      discription:
        "割愛",
    },
    {
      id: 3,
      name: "ガトーショコラ",
      path: "cake3",
      discription:
        "割愛",
    },
    {
      id: 4,
      name: "チーズケーキ",
      path: "cake4",
      discription:
        "割愛",
    },
  ];
  const { scrollYProgress } = useScroll();
  return (
    <>
      <motion.div
        style={{ scaleX: scrollYProgress }}
        className="fixed top-0 left-0 right-0 h-5 bg-red-500 origin-left"
      />
      <div className="flex justify-center items-center min-h-screen bg-gray-100">
        <div className="bg-white p-8 rounded-lg shadow-lg max-w-sm my-20">
          <h1 className="text-2xl font-bold mb-6 text-center bg-red-200 p-5 rounded-lg">
            色んなケーキ
          </h1>
          <ul>
            {cakeList.map((cake) => {
              return (
                <motion.li
                  viewport={{ once: true }}
                  initial={{ opacity: 0 }}
                  whileInView={{ opacity: 1 }}
                  transition={{ delay: 1 }}
                  className="my-20"
                >
                  <h1 className="text-2xl font-bold mb-6">{cake.name}</h1>
                  <img
                    src={`/src/assets/image/${cake.path}.png`}
                    className="w-[700px]"
                  />
                  <p className="text-lg">{cake.discription}</p>
                </motion.li>
              );
            })}
          </ul>
        </div>
      </div>
    </>
  );

スクロール地点でふわっと表示させるところはmotion.liタグの中に書いています。
whileInViewで画面内に表示された時の挙動を指定して、viewportで一度だけそのフェードインが実行されるようにします。4行で実装できました。

上のスクロールに合わせて伸びるバーはframer-motionのカスタムフックuseScrollを使っています。
useScrollはスクロールの絶対座標scrollX, Yとプログレスの進行割合をscrollXProgress, scrollYProgressで4つの値を返しましす。
今回はy座標の進行割合だけ確認したいのでscrollYProgressだけ取り出しました。

framer-motionは初めて触ったのですが、感覚的に非常に分かりやすかったです。

参考にさせていただいた記事

https://zenn.dev/y_ta/books/62a676a1d22982

NCDCエンジニアブログ

Discussion