📽️
Next.js + Framer Motion で簡単にページ遷移アニメーション実現
概要
Next.js でページ遷移時に Framer Motion によるアニメーションをつけようとし、調べて出てくる情報でなかなか実現できなかったが、あっさり簡単な方法で実現できたので解説します。
経緯
出てくる情報通りにmain
の要素自体をmotion.main
にすると、リロード時にはアニメーションされるが、router.push
やNextLink
で遷移したときにアニメーションされなかった。
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 👩💻👨💻
Discussion