📽️

Next.js + Framer Motion で簡単にページ遷移アニメーション実現

2022/11/26に公開

概要

Next.js でページ遷移時に Framer Motion によるアニメーションをつけようとし、調べて出てくる情報でなかなか実現できなかったが、あっさり簡単な方法で実現できたので解説します。

経緯

出てくる情報通りにmainの要素自体をmotion.mainにすると、リロード時にはアニメーションされるが、router.pushNextLinkで遷移したときにアニメーションされなかった。

AnimatePresence を使わなくても行けた

Next.js + Framer Motion で調べると絶対にこれを使うパターンが出てきますが、
あれこれ設置位置を変えてみても全く機能しなかった。

以下の解決策の方法でマウントのアニメーションは実現できたが、
これだとアンマウントのアニメーションは実行されないので、やはりAnimatePresenceを使った方法は必要そうです。

解決策 - そもそもページ遷移時にマウントされるものにアニメーションをかければよかった

自分が現在開発しているNext.jsアプリはよくあるヘッダーとサイドバーがあるダッシュボードレイアウトです。

そして、メインのコンテンツ部分となるところはすべてPageという共通コンポーネントでラップして、ページのレイアウトを固定していました。

ページ遷移時もそのPageコンポーネント単位でマウント切り替えされるので、そのコンポーネント直下に <motion.div> をさしめばよいだけの話でした。

今回のケースではBoxコンポーネントをmotion.divに変更しています。

components/Page.tsx
const variants = {
  hidden: { opacity: 0, x: -200, y: 0 },
  enter: { opacity: 1, x: 0, y: 0 },
  exit: { opacity: 0, x: 0, y: -100 },
};

const Page = forwardRef<HTMLDivElement, PageProps>(
  (
    {
      children,
      title = '',
      meta,
      BoxProps,
      ContainerProps,
      needPermit,
      PermitProps,
      PageHeaderPros,
      StackProps,
    },
    ref
  ) => (
    <>
      <Head>
        <title>{`${title} | サイト名`}</title>
        {meta}
      </Head>
      <Box
        component={motion.div}
        variants={variants} // Pass the variant object into Framer Motion
        initial="hidden" // Set the initial state to variants.hidden
        animate="enter" // Animated state to variants.enter
        exit="exit" // Exit state (used later) to variants.exit
        transition={{ type: 'linear' }} // Set the transition to linear
        ref={ref}
        {...BoxProps}
      >
	  <Container {...ContainerProps}>
	    <PageHeader {...PageHeaderPros} heading={title} />
	    {children}
	  </Container>
      </Box>
    </>
  )
);

export default Page;
pages/example.tsx
import { Page } from '@/components'

// 省略

export default function PageExample() {
  // 省略
  return (
    <Page>
      // ページのコンテンツ
    </Page>
  )
}

参考

Animating Next.js page transitions with Framer Motion - DEV Community 👩‍💻👨‍💻

Next.js + Framer Motion でページ遷移アニメーションを実装する - Qiita

Discussion