[Next.js] View Transitionで画面遷移にアニメーションを付ける
環境
以下の環境で動作確認を行った。
- React v19.0.0
- Next.js v15.2.3
- use App Router
- TypeScript v5.8.2
実装
いろいろな手法があるが、今回はなるべく簡素に実装していきたいと思う。
View Transition API
View Transition APIを利用して画面遷移時にアニメーションを付与する。まずは、アニメーションの実装をCSSで定義していく。
今回は以下のAPIを利用する。
::view-transition-old
::view-transition-new
::view-transition-old
このセレクタは 古いビュー(遷移前のページの要素) に適用される。
基本的な構文は以下の通り。
::view-transition-old(<pt-name-selector >) {
/* ... */
}
今回、<pt-name-selector>
はcross-fade
という名称にして以下のようなアニメーションを定義する。
@keyframes fadeOut {
0% {
opacity: 1;
}
to {
opacity: 0;
}
}
::view-transition-old(cross-fade) {
animation: fadeOut 0.4s var(--easing-ease-in-out-circ) forwards;
}
::view-transition-new
このセレクタは 新しいビュー(遷移後のページの要素) に適用される。
基本的な構文は以下の通り。
::view-transition-new(<pt-name-selector >) {
/* ... */
}
::view-transition-old
と同じく、<pt-name-selector>
はcross-fade
という名称にして以下のようなアニメーションを定義する。
@keyframes fadeIn {
0% {
opacity: 0;
}
to {
opacity: 1;
}
}
::view-transition-new(cross-fade) {
opacity: 0;
animation: fadeIn 0.6s var(--easing-ease-out) 0.2s forwards;
}
アクセシビリティ
アクセシビリティ考慮(ユーザーの負担軽減)のため、視差効果を減らす(アニメーションの無効設定)を行うこともある。
その場合はprefers-reduced-motion
と組み合わせて、視差効果を減らすが有効ではない場合にのみview-transitionが有効になるようにすると良い。
@media not (prefers-reduced-motion: reduce) {
::view-transition-old(cross-fade) {
/* */
}
::view-transition-new(cross-fade) {
/* */
}
}
<ViewTransition>
コンポーネントを利用する
View Transition API を React で実験的に利用できるようになった。unstable_ViewTransition
コンポーネントを利用して簡単に実装ができる。
Next.jsでViewTransitionを有効にする
Next.jsのv15.2.0以降であることが条件だが、以下の設定(experimental.viewTransition
)を有効にするとViewTransitionを利用できるようになる。
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
viewTransition: true,
},
};
module.exports = nextConfig;
ViewTransitionを導入する
各要所に入れても良いが、src/app/layout.tsx
に入れると一括でTransitionを付与できる(アニメーションの要件に応じて対応箇所を細かく決める必要はあるが、今回はシンプルに実装するためそうする)。
事前に用意したスタイルの名称(cross-fade
)をname
に指定した<ViewTransition>
コンポーネントをアニメーションさせたい要素に包括する。
unstable_ViewTransition
は分かりやすいように(コンポーネントの命名規則も踏まえて)、ViewTransition
という名称にしておく。
// src/app/layout.tsx
import { unstable_ViewTransition as ViewTransition } from "react";
export default function Layout({ children }: { children: ReactNode }) {
return (
<html lang="ja">
<body>
<Header />
<ViewTransition name="cross-fade">
<Main>{children}</Main>
</ViewTransition>
<Footer />
</body>
</html>
);
}
以上の設定でNext.jsの遷移での視覚効果が有効になる。
Discussion