はじめまして、もるふぉです。
エンジニアをやりながら、今はほぼコードを書かない開発スタイルに移行しました。
「書けないから書かない」じゃなくて、「書けるから書かなくていい」という話です。
実案件ベースで気づいたことだけ書いています。
よければXもフォローしてもらえると嬉しいです → X(@morphox_ai)
ページ遷移アニメーション、ずっと後回しにしていませんでしたか?
「framer-motionの AnimatePresence 、ルーティングとの統合、exitプロパティ...」と考えただけで気が重くなって、「まあ、動けばいいか」でリリースしてしまった経験、ありますよね。
2026年4月3日、Next.js公式がコーディングエージェント向けスキル「react-view-transitions」を発表しました。
この発表をきっかけに、ReactのViewTransition機能を改めて整理してみます。
Next.js 15.2以降では experimental.viewTransition フラグひとつで有効になり、framer-motionを使わずにスムーズなページ遷移アニメーションが実装できます。
framer-motionの設定ファイルと格闘していた日々、もう終わりにしませんか。
React ViewTransitionとは何か
View Transitions APIの概要
View Transitions APIは、ブラウザがネイティブで提供するアニメーション機構です。
ページの状態が変わるとき、ブラウザが「変更前のスナップショット」と「変更後のライブ表現」を自動的に作成し、その間をスムーズにアニメーションしてくれます。
「それ、JavaScriptで全部やってたやつですよね?」という話です。
従来はJavaScriptで複雑なアニメーションライブラリを組み込む必要がありましたが、View Transitions APIではCSSの疑似要素(::view-transition-old、::view-transition-new)でアニメーションを定義するだけで動きます。
しかもブラウザレベルでハードウェアアクセラレーションされているので、JSで頑張って書いたアニメーションより、むしろ滑らかになることすらあります。
React / Next.jsネイティブ統合のViewTransitionが新しい理由
ここが面白いところなんです。
ReactのCanaryチャンネルでは コンポーネントが利用できます。
これまでのView Transitions APIは document.startViewTransition() を手動で呼び出す必要があり、Reactの宣言的なパラダイムとは相性がよくなかったんですよね。
「イベントハンドラーの中でAPIを呼んで、その中でstateを更新して...」という手続き的なコードを書かざるを得なかった。
はこれを解決します。
コンポーネントで子要素をラップするだけで、startTransition と連動してアニメーションが自動発火します。
しかも enter、exit、update、share といったpropsで、どのタイミングのアニメーションを適用するか宣言的に指定できます。
Next.jsでは next.config.ts に1行追加するだけで、ルーティング遷移時に自動的にViewTransitionが有効になります。
つまり、既存コードをほぼ触らずにアニメーションが動き出す、ということです。
next-view-transitions(旧サードパーティ)とReactネイティブViewTransitionの違い
「あ、それ next-view-transitions でやってたやつですよね?」という方もいると思います。
これまでNext.jsでView Transitionsを使うには、Shu Ding氏が作った next-view-transitions というサードパーティパッケージが定番でした。
このパッケージは でアプリをラップし、専用の コンポーネントを使う設計でした。
対して、Reactネイティブの を活用する現在のアプローチでは、追加のProviderやカスタムLinkは不要です。
Next.jsの next/link がそのまま使えるので、既存コードへの影響が最小限で済みます。
ここが一番大きな違いですね。
既存プロジェクトへの導入コストが、サードパーティ版と比べて格段に下がっています。
では実際に、どう動かすのかを見てみましょう。
React ViewTransitionのセットアップ — next.config.tsの1行だけ
Next.jsの動作環境と必要バージョン
ViewTransitionを使うために必要な環境は以下のとおりです。
は2026年4月時点で react@canary / react@experimental チャンネルで利用可能です。
安定版のReact 19には含まれていないため、Next.js 15.2以降の experimental.viewTransition フラグを通じて利用するのが現実的な選択肢です。
なお、このフラグは実験的機能であり、今後変更される可能性があります。
next.config.tsにexperimental.viewTransitionを追加する
設定を見てください。
本当にこれだけです。
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
viewTransition: true,
},
};
export default nextConfig;「え、これだけ?」って思いましたよね。
これだけで、Next.jsのルーター遷移時にView Transitions APIが自動的に有効になります。
experimental.viewTransition を有効にすると、Next.jsがナビゲーション時に自動で document.startViewTransition() を呼び出してくれるので、開発者は コンポーネントの配置に集中できます。
framer-motionでAnimate Presenceを設定していた時間を思い出すと、なかなか感慨深いです。
ブラウザ対応状況(Chrome / Safari / Firefox)
「でも、ブラウザ対応が不安で...」という気持ち、わかります。
2026年4月時点のブラウザ対応状況をまとめます。
重要なのは、View Transitions APIはグレースフルデグラデーションする設計だという点です。
非対応ブラウザではアニメーションがスキップされるだけで、DOM更新自体は正常に動作します。
つまり、非対応ブラウザで見ても「壊れる」のではなく「アニメーションなしで普通に動く」だけ。
リスクゼロで今すぐ導入できるんですよ。
これ、結構大事なポイントです。
ブラウザ対応を盾にして後回しにできない理由がなくなりました。
ではいよいよ、コンポーネントの実装を見てみましょう。
基本 — Next.jsでのViewTransitionナビゲーション間アニメーション
ViewTransitionコンポーネントの基本的な使い方
の使い方はとてもシンプルです。
アニメーションさせたい要素をラップするだけ。
import { ViewTransition } from 'react';
function MyComponent() {
return (
<ViewTransition enter="auto" exit="auto">
<div className="card">
<h2>コンテンツ</h2>
<p>この要素が表示・非表示時にアニメーションします</p>
</div>
</ViewTransition>
);
}ポイントは、状態変更を startTransition で包む必要があることです。
import { useState, startTransition } from 'react';
function App() {
const [show, setShow] = useState(false);
return (
<>
<button
onClick={() => {
startTransition(() => {
setShow(prev => !prev);
});
}}
>
{show ? '非表示' : '表示'}
</button>
{show && <MyComponent />}
</>
);
}startTransition で状態更新をラップしないとViewTransitionは発火しません。
「動かない!」と5分悩む前に、ここを確認してください。
最初にハマりやすいポイントなので、覚えておいてください。
enter / exit / update / shareの各propの使い分け
には4つのアニメーションタイプを指定するpropsがあります。
enterexitupdateshare料理に例えると、「入店・退店・席移動・テーブル間の移動」それぞれに違う演出を当てるイメージです。
それぞれに "auto"(デフォルトアニメーション)、"none"(無効化)、またはCSSクラス名の文字列を指定できます。
<ViewTransition
enter="slide-in"
exit="slide-out"
update="none"
default="auto"
>
<Card />
</ViewTransition>default propを指定すると、個別に設定していないタイプすべてにそのアニメーションが適用されます。
全部設定しなくていい、というのが地味に助かります。
React ViewTransitionのEnter/Exit実装コード全体
Enter/Exitアニメーションの実用的な例を示します。
// components/AnimatedItem.tsx
import { ViewTransition } from 'react';
export function AnimatedItem({ children }: { children: React.ReactNode }) {
return (
<ViewTransition enter="fade-slide-in" exit="fade-slide-out" default="none">
{children}
</ViewTransition>
);
}/* styles/transitions.css */
::view-transition-new(.fade-slide-in) {
animation: fadeSlideIn 300ms ease-out;
}
::view-transition-old(.fade-slide-out) {
animation: fadeSlideOut 300ms ease-in;
}
@keyframes fadeSlideIn {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeSlideOut {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(-20px);
}
}CSSを書くだけでアニメーションが動くのは、framer-motionのJSベースのアニメーション定義に比べると本当にラクですね。
「JavaScriptでアニメーションを管理する」という考え方から解放される感覚があります。
ここまでで基本的な使い方はわかりました。
次が、ViewTransitionの中でも特に「お、これはすごい」と思った機能です。
共有要素トランジション — View Transitions APIでリストから詳細へスムーズに遷移
name propで要素を紐付ける
正直、これを初めて動かしたとき、鳥肌が立ちました。
共有要素トランジションは、ViewTransitionの目玉機能です。
一覧ページのサムネイルと詳細ページのヒーロー画像が、同じ要素として滑らかに移動するあの演出です。
name propに同じ文字列を指定するだけで実現できます。
// 一覧ページ側
<ViewTransition name="product-image">
<img src={product.thumbnail} alt={product.name} />
</ViewTransition>
// 詳細ページ側
<ViewTransition name="product-image">
<img src={product.heroImage} alt={product.name} />
</ViewTransition>ブラウザが自動的に2つの要素間をアニメーションしてくれます。
想像してみてください。
ECサイトで商品一覧から商品詳細に遷移したとき、サムネイルが滑らかに拡大しながらヒーロー画像になる。
これが name propひとつで実現できるんですよ。
Next.js App Routerでの一覧ページと詳細ページの実装例
Next.js App Routerでの実装例を見てみましょう。
// app/products/page.tsx
import Link from 'next/link';
import { ViewTransition } from 'react';
export default function ProductList() {
return (
<div className="grid">
{products.map((product) => (
<Link key={product.id} href={`/products/${product.id}`}>
<ViewTransition name={`product-${product.id}`}>
<div className="product-card">
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
</div>
</ViewTransition>
</Link>
))}
</div>
);
}// app/products/[id]/page.tsx
import { ViewTransition } from 'react';
export default function ProductDetail({ params }: { params: { id: string } }) {
const product = getProduct(params.id);
return (
<div className="detail">
<ViewTransition name={`product-${product.id}`}>
<img
src={product.image}
alt={product.name}
className="hero-image"
/>
</ViewTransition>
<h1>{product.name}</h1>
<p>{product.description}</p>
</div>
);
}next/link でのナビゲーション時にViewTransitionが発火する点がポイントです。
router.push() でも動作しますが、next/link を使うのが最もシンプルです。
view-transition-nameの重複を避けるパターン
一点だけ、落とし穴があります。
name propの値はアプリ全体で一意でなければなりません。
同じ name を持つ が同時にマウントされるとエラーになります。
一覧ページでは複数のカードが同時に表示されるため、動的なIDを使って一意性を担保してください。
// OK: 動的IDで一意にする
<ViewTransition name={`product-${product.id}`}>
// NG: 固定名だと一覧ページで重複する
<ViewTransition name="product-image">最初に見落としがちなポイントなので、気をつけてくださいね。
さらにここからが、実際のアプリ開発で「やっぱり必要だよな」と感じる場面の話です。
ページスライド — Next.jsでforward / backwardの方向別ViewTransitionアニメーション
Transition Typesで方向を指定する
ページを「進む/戻る」で動きの方向を変えたい、と思ったことはありませんか?
ネイティブアプリのUIと同じ、あの感覚です。
addTransitionType と組み合わせてTransition Typesを使うと、これが実現できます。
import { ViewTransition, addTransitionType } from 'react';
import { startTransition } from 'react';
function Navigation() {
const handleForward = () => {
startTransition(() => {
addTransitionType('slide-forward');
router.push('/next-page');
});
};
const handleBack = () => {
startTransition(() => {
addTransitionType('slide-backward');
router.back();
});
};
return (
<>
<button onClick={handleBack}>戻る</button>
<button onClick={handleForward}>進む</button>
</>
);
}レイアウトファイルで、Transition Typeに応じたアニメーションを指定します。
// app/layout.tsx
import { ViewTransition } from 'react';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<ViewTransition
default={{
'slide-forward': 'slide-left',
'slide-backward': 'slide-right',
default: 'auto',
}}
>
{children}
</ViewTransition>
</body>
</html>
);
}ViewTransitionのCSSアニメーション定義
方向別のスライドアニメーションをCSSで定義します。
/* 前方向(左にスライド) */
::view-transition-old(.slide-left) {
animation: slideOutLeft 400ms ease-in-out;
}
::view-transition-new(.slide-left) {
animation: slideInRight 400ms ease-in-out;
}
/* 後方向(右にスライド) */
::view-transition-old(.slide-right) {
animation: slideOutRight 400ms ease-in-out;
}
::view-transition-new(.slide-right) {
animation: slideInLeft 400ms ease-in-out;
}
@keyframes slideOutLeft {
to { transform: translateX(-100%); }
}
@keyframes slideInRight {
from { transform: translateX(100%); }
}
@keyframes slideOutRight {
to { transform: translateX(100%); }
}
@keyframes slideInLeft {
from { transform: translateX(-100%); }
}ネイティブアプリのような「進む/戻る」のスライドが、CSSだけで実現できるのは本当に気持ちいいですね。
Next.jsレイアウトとViewTransitionを組み合わせた実装コード全体
レイアウトとCSSを組み合わせた完全な実装例です。
// app/layout.tsx
import { ViewTransition } from 'react';
import './transitions.css';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja">
<body>
<nav>
<NavigationButtons />
</nav>
<ViewTransition
default={{
'slide-forward': 'slide-left',
'slide-backward': 'slide-right',
default: 'auto',
}}
>
<main>{children}</main>
</ViewTransition>
</body>
</html>
);
}これだけで、ページ全体がスライドアニメーション付きで遷移します。
framer-motionでこれをやろうとすると、AnimatePresence、motion.div、exitプロパティの設定、ルーティングとの統合...と、かなりの手間がかかっていたはずです。
その差を実感したくなりませんか?
次は、ローディング中のUXを改善する話です。
スムーズなローディング遷移 — ViewTransitionとSuspenseの組み合わせ
ViewTransitionとSuspenseを組み合わせた場合の動作
「スケルトンUIからコンテンツが切り替わるときの、あの唐突な感じ」が気になっていた方、ここを見てください。
と を組み合わせると、ローディング状態から実コンテンツへの遷移もアニメーションできます。
import { Suspense } from 'react';
import { ViewTransition } from 'react';
function Page() {
return (
<Suspense
fallback={
<ViewTransition>
<LoadingSkeleton />
</ViewTransition>
}
>
<ViewTransition>
<ActualContent />
</ViewTransition>
</Suspense>
);
}この場合、LoadingSkeleton から ActualContent への切り替え時に、ブラウザがクロスフェードアニメーションを自動適用します。
フォールバック表示とフェードイン
もう一つのパターンとして、 で を包む方法もあります。
<ViewTransition>
<Suspense fallback={<Skeleton />}>
<AsyncComponent />
</Suspense>
</ViewTransition>この書き方だと、フォールバックから実コンテンツへの切り替えが update アニメーションとして扱われます。
用途に応じて使い分けてください。
スケルトンUIからコンテンツへの遷移がなめらかになるだけで、体感的な速度が全然違います。
「実際の速度は変わってないのに速く感じる」という、UXの魔法ですね。
ユーザー体験に直結する部分なので、ぜひ試してみてほしいですね。
コンポジション — 複数のViewTransitionを組み合わせる応用パターン
ここからは応用的なテクニックです。
基本の使い方を押さえた上で、実務でよく使う設計パターンを紹介します。
ネストしたViewTransitionの優先度ルール
はネストできます。
内側のViewTransitionが外側よりも優先されるルールです。
<ViewTransition default="auto">
<header>ヘッダー(外側のautoが適用)</header>
<ViewTransition enter="slide-in" exit="slide-out">
<main>メインコンテンツ(内側の設定が優先)</main>
</ViewTransition>
<footer>フッター(外側のautoが適用)</footer>
</ViewTransition>CSSのカスケードに近い考え方で直感的ですよね。
この仕組みにより、ページ全体にはデフォルトのフェードを適用しつつ、メインコンテンツだけスライドアニメーションにする、といった細かい制御が可能です。
実用的な設計パターン
実務では以下のような階層設計が使いやすいです。
// app/layout.tsx - グローバルレイアウト
<ViewTransition default="auto">
<Header />
<ViewTransition
default={{
'slide-forward': 'slide-left',
'slide-backward': 'slide-right',
default: 'fade',
}}
>
{children}
</ViewTransition>
<Footer />
</ViewTransition>ヘッダーとフッターはデフォルトのクロスフェード、ページ本体は方向に応じたスライド、という構成です。
コンポジションのおかげで「全体のルール」と「個別のルール」を自然に分離できます。
Reactのコンポーネント設計とも非常に相性がいいですね。
本番に出す前に、あとひとつだけ確認してほしいことがあります。
アクセシビリティ対応は必須
prefers-reduced-motionの実装方法
アニメーションは見た目の改善になりますが、前庭障害のあるユーザーにとっては体調悪化の原因になることがあります。
「アニメーションを減らす設定」をOSで有効にしているユーザーが、予期しないアニメーションで不調を感じる、というのは本当に避けなければいけない事態です。
prefers-reduced-motion メディアクエリで、ユーザーの設定を尊重するのは必須です。
CSSで一括無効化するスニペット
以下のCSSをグローバルスタイルに追加してください。
@media (prefers-reduced-motion: reduce) {
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
transition: none !important;
}
}たった4行です。
これがあるかないかで製品の品質が変わります。
本番に出すコードには必ず入れてくださいね。
まとめ — react-view-transitionsで何が変わるか
ViewTransitionがもたらす変化をまとめます。
だけで完結next/linkがそのまま使えるnext.config.tsの1行で有効化「ページ遷移アニメーションは面倒だから後回し」にしていたプロジェクトでも、next.config.ts に1行足すだけで始められます。
コード量は圧倒的に少なく、パフォーマンスはブラウザネイティブで最適化済み。
しかもグレースフルデグラデーションするので、非対応ブラウザでも壊れない。
個人的には、framer-motionを入れる理由がどんどん減っていると感じています。
もちろんframer-motionにはレイアウトアニメーションやジェスチャー対応など固有の強みもありますが、ページ遷移に限って言えば、View Transitions APIの方がシンプルで軽量です。
まずこれだけやってみてください。
next.config.tsにexperimental: { viewTransition: true }を追加- 動かしたい要素を
でラップ - ブラウザで確認
この3ステップ、5分かかりません。
アプリの印象がガラッと変わる体験を、ぜひ手を動かして確認してみてください。
AIコーディングツールの最新動向に興味がある方は、こちらの記事もどうぞ。
Cursor 3まとめ:VS Code脱却、エージェントが98%書く時代のIDEはこう変わった
最後まで読んでくれてありがとうございます。
よければXもフォローしてもらえると嬉しいです → X(@morphox_ai)



💬 コメント
ログイン か 会員登録 するとコメントできます