🍆

【Framer Motion】スワイプでサイドメニューを閉じる

2023/09/21に公開

スマホのアプリケーションでよくあるスワイプしたらサイドメニューを閉じるという操作。
Framer Motionを使えばWebサイトでも簡単に実現できます。

完成イメージ

動画のようにちょっと動かしただけでは閉じません。
また、動かした後にカーソルを止めた(迷ったような動き)ときも閉じません。
勢いよく左にスワイプしたときに閉じる定番のヤツです。

準備と実装

Framer Motionをインストールしていない場合は下記を実行しておきます。

npm install framer-motion

下記はタイトルのモノの実装例です。

import { motion } from "framer-motion";

const GlobalMenu = ({ children }: {children: React.ReactNode}) => {
  // jotai による状態管理
  const { isOpenGlobalMenu, closeGlobalMenu } = useGlobalMenu();

  return (
    <div className="fixed z-[5000] top-0 left-0 w-[30rem] h-[100vh]">
      <motion.div
        drag="x" // 左右方向の動きに限定する
        dragConstraints={{ right: 0 }} // 右方向の制限
        dragElastic={{ right: 0 }} // 右側に動かないようにする
        dragMomentum={false} // 右方向に連続してドラッグすると動く問題を回避
        dragSnapToOrigin={true} // 離したときに元の位置に戻す
        onDragEnd={(event, info) => {
	  // info.volocity -> 要素が現在感じている速度感
	  // info.offset -> どれだけ動いたか
          if (info.velocity.x <= -10 && info.offset.x <= -50) {
	    // 閉じる条件に合致したので閉じる
            closeGlobalMenu();
          }
        }}
        className="h-full bg-white"
      >
        {children}
      </motion.div>
    </div>
  );
}

おわり

Framer Motionは魔法ですね!
とても簡単に実装できました。

しかし、小さな問題がありまして、
閉じるときに若干右に戻るような動きが残っています。
これを解決するには onDrag を使ってやる必要がありそうなのですが、今の自分としてはひとまず現状で良しとしています。

ちなみに開く側のドラッグ操作はブラウザには適していないと思います。
というのも、Android Chromeなどでは両端からスワイプすると戻る操作になるので!

Discussion