View Transitions APIは、DOMの更新前後をブラウザがスナップショットとして撮り、その差分をCSSアニメーションでつなぐ仕組みです。同一ページ内の表示切り替えだけでなく、別ページへの移動でも演出を途切れさせずに済みます。ただし「使えるかどうか」の答えは機能単位で割れており、同一ドキュメント内の遷移は主要ブラウザすべてで動く一方、ページをまたぐクロスドキュメント遷移はFirefoxが未対応のままです。この差を踏まえないまま実装すると、環境によって「動くはずの演出が出ない」という問い合わせにつながります。本記事の対応状況はすべて2026年8月時点、@mdn/browser-compat-data 8.0.10(データ生成 2026年8月6日)と web-features 3.34.3 に基づきます。
まとめ
- 同一ドキュメント遷移(
document.startViewTransition())はChrome 111・Safari 18・Firefox 144で対応し、2025年10月14日にBaselineへ到達済み - Chrome 126が2024年6月11日に載せたクロスドキュメント遷移(
@view-transition)は、2年後の現在もFirefox未対応でBaseline未到達 - MPAでの有効化はCSS 2行で済むが、Firefoxでは演出なしの通常遷移に落ちる前提で設計する
- 現行のFirefox ESR 140系は既定でView Transitions APIが動かないため、社内配布環境では機能要件に入れない
- 未対応ブラウザ向けには
document.startViewTransitionの有無を見てDOM更新だけ走らせる分岐を必ず置く
以降で、2つの遷移モードの違い、機能別の対応バージョン、実装手順とつまずきどころを順に見ていきます。
View Transitions APIの仕組みと2つの遷移モード
このAPIは、遷移前の画面と遷移後の画面をそれぞれ静止画として取り込み、疑似要素ツリー(::view-transition-old() と ::view-transition-new())としてページ最上部に重ねます。開発者が書くのは、その疑似要素に対するCSSアニメーションだけです。手続き型のアニメーション制御をブラウザ側へ寄せた点が、style.transitionやsetTimeoutを並べる従来手法との決定的な違いになります。
同一ドキュメント遷移:startViewTransition()が担う範囲
SPAのように1つのドキュメント内で表示を差し替えるケースでは、DOMを書き換える処理をコールバックとしてdocument.startViewTransition()へ渡します。ブラウザは呼び出し時点の画面を撮り、コールバックの実行を待ってから新しい画面を撮り、両者をクロスフェードでつなぎます。戻り値のViewTransitionオブジェクトからは、アニメーション開始可能になった時点を示すready、完了時に解決するfinished、DOM更新の完了を示すupdateCallbackDoneの各Promiseと、途中で演出だけ打ち切るskipTransition()が取れます。
注意したいのは、startViewTransition()を呼んだ瞬間にページの可視性がhiddenだと、遷移が丸ごとスキップされる点です。タブが非アクティブなときやウィンドウが最小化されているときに発火する処理では、演出の完了を前提にした後続処理を書かないでください。
クロスドキュメント遷移:@view-transitionが担う範囲
MPAでページをまたぐ場合はJavaScriptを書かず、遷移元と遷移先の両方のCSSに@view-transitionルールを置いてオプトインします。MDNによればnavigation: autoが効くのは、同一オリジンであり、クロスオリジンのリダイレクトを挟まず、ナビゲーション種別がtraverse・push・replaceのいずれかである場合です。さらにpushとreplaceでは、ユーザーがページ内容を操作したことが起点になっている必要があります。外部サイトからの流入直後にスクリプトで遷移させても演出は出ない、ということです。
対応ブラウザとBaseline状況【2026年8月時点】
「View Transitions APIは使えるのか」という問いは、同一ドキュメント遷移とクロスドキュメント遷移で答えが割れます。ブラウザ列はBCD 8.0.10の値、Baseline列はweb-features 3.34.3の判定です。Baseline(Newly available)は、デスクトップのChrome・Edge・Firefox・Safariに加え、Chrome Android・Firefox Android・Safari iOSでも利用可能になって初めて成立します。
| 機能 | Chrome / Edge | Safari | Firefox | Baseline |
|---|---|---|---|---|
| 同一ドキュメント遷移 | 111 | 18 | 144 | 到達(2025-10-14) |
| クロスドキュメント遷移 | 126 | 18.2 | 未対応 | 未到達 |
| view-transition-class | 125 | 18.2 | 144 | 到達(2025-10-14) |
| 遷移タイプ(types) | 125 | 18.2 | 147 | 到達(2026-01-13) |
| match-element | 137 | 18.4 | 144 | 個別指定なし |
| pagereveal | 123 | 18.2 | 未対応 | 個別指定なし |
| pageswap | 124 | 18.2(部分) | 未対応 | 個別指定なし |
| 要素単位の遷移 | 147 | 未対応 | 未対応 | 未到達 |
モバイル版(Chrome Android・Safari iOS・Firefox Android)の対応バージョンは、上表のすべての機能でデスクトップ版と同一です。Baseline欄の「個別指定なし」は、web-featuresがその機能を独立した項目として登録しておらず、View Transitions全体の判定に含めていることを示します(表のブラウザ列がそのまま実態です)。クロスドキュメント遷移の欄は@view-transition、要素単位の欄はview-transition-scopeとElement.startViewTransition()を指します。
実装の可否を分けるのはブラウザ名ではなく機能単位です。Firefoxが取り残されているのはクロスドキュメント遷移まわり(@view-transition・pageswap・pagereveal)で、要素単位の遷移についてはSafariも含めてChromium系のみが実装しています。Baselineに到達した機能から順に採用していく進め方は、CSS Anchor Positioningのような新しいCSS機能を導入するときと同じ判断軸です。
クロスドキュメント遷移がBaseline未到達である理由
同一ドキュメント遷移は、最後発だったFirefoxが144(2025年10月14日リリース)で実装したことでBaselineの条件を満たしました。一方クロスドキュメント遷移は、Firefoxが@view-transitionルールもpageswap/pagerevealイベントも未実装です。pageswapについてはBugzillaに実装課題(bugzil.la/1881438)が残っている状態で、リリース版には入っていません。
Safari側にも制約があります。Safari 18.2はpageswapを部分実装で、クロスオリジンのナビゲーションではイベントが発火しません(WebKit bug 306447)。遷移方向の判定をこのイベントだけに任せる設計は、Safariで分岐が抜けます。
Firefox ESR配布環境での可否判断
社内システムやBtoBの業務画面では、ブラウザをESR(延長サポート版)で配布している組織が少なくありません。ここが実務上いちばん問題になります。現行のFirefox ESRは140.13.0esrで、ベースは2025年6月24日リリースの140系です。同一ドキュメント遷移の対応は144からなので、現行ESRでは既定でView Transitions APIが動きません。厳密には140系にもdom.viewTransitions.enabledという設定が存在しますが、既定は無効で、利用者にabout:configを触らせる前提の機能を業務要件に据えるのは現実的ではありません。
次期ESRの153系は2026年7月21日にリリース済みで、こちらへ移行すれば同一ドキュメント遷移も遷移タイプ(147以降)も利用できます。現行ESRの140は通常版の153に対して13メジャー版前、ESR世代でいえば1つ前にあたります。ただしクロスドキュメント遷移はFirefox本体が未対応のため、ESRを更新しても解決しません。ESRを前提とする案件では、View Transitions APIは「対応環境でのみ上乗せされる演出」と位置づけ、要件定義書の機能要件には書かないでください。受け入れテストの合否条件に入れてしまうと、環境差がそのまま不具合票になります。
同一ドキュメント遷移の実装手順
未対応ブラウザを壊さない最小構成
実装の起点は、APIの存在チェックと分岐です。document.startViewTransitionが無い環境ではDOM更新関数をそのまま呼び、ある環境では同じ関数をコールバックとして渡します。更新処理を関数に切り出しておけば、分岐で処理が二重化しません。
const titles = { 1: "View Transitions API の概要", 2: "対応ブラウザ" };
const gallery = document.querySelector("#gallery");
function showDetail(id) {
gallery.dataset.view = "detail";
gallery.querySelector("#detail-title").textContent = titles[id];
}
document.querySelector("#open").addEventListener("click", () => {
// 未対応ブラウザでは DOM 更新だけを実行し、遷移演出は諦める
if (!document.startViewTransition) {
showDetail(1);
return;
}
document.startViewTransition(() => showDetail(1));
});
この形なら、Firefox ESRでもSafari 17以前でも表示は正しく切り替わり、演出だけが省かれます。逆に分岐を省いてdocument.startViewTransition(() => ...)を直接呼ぶと、未対応環境では例外が出て画面更新そのものが止まります。
view-transition-nameによる要素の対応付け
既定の演出は画面全体のクロスフェードです。特定の要素を遷移前後で同一物として扱わせたい場合は、その要素にview-transition-nameを付け、生成される疑似要素へアニメーションを指定します。
.gallery-hero {
view-transition-name: hero-image;
}
::view-transition-old(hero-image),
::view-transition-new(hero-image) {
animation-duration: 320ms;
animation-timing-function: cubic-bezier(0.2, 0, 0, 1);
}
この値は描画中の要素ごとに一意でなければなりません。同じ名前の要素が同時に2つ描画されていると、ViewTransition.readyがrejectされ遷移はスキップされます。一覧から詳細へ移るUIでは、クリックされたカードにだけ動的に名前を付け、スナップショット取得後に外す運用が定石です。Chrome 137・Safari 18.4・Firefox 144以降ならview-transition-name: match-elementが使え、対象要素へ一意な名前を自動で割り当てられます。
クロスドキュメント遷移(MPA)の実装手順
CSS 2行での有効化と両ページ必須の理由
MPAでの有効化は、遷移元と遷移先の双方のCSSに次のルールを置くだけです。JavaScriptは不要です。
@view-transition {
navigation: auto;
}
片側にしか書いていないと遷移は発生しません。遷移元は「これから離れる画面を撮ってよい」と宣言する側、遷移先は「撮られた画面と自分をつないでよい」と宣言する側で、両方の同意が要るためです。サイト共通のCSSに置くのが確実です。加えて、同一オリジンであること、クロスオリジンのリダイレクトを挟まないこと、ナビゲーション種別がtraverse・push・replaceであることも条件になります。対応ブラウザではリンククリックがそのまま遷移のトリガーになり、未対応ブラウザでは従来どおりのページ読み込みになります。エラーにはならないため、Firefoxで演出が出ないという問い合わせが来ても実装ミスとは限りません。
pageswap・pagerevealによる遷移方向の出し分け
戻る操作と進む操作でアニメーションの向きを変えたい場合は、遷移元で発火するpageswap(Chrome 124・Safari 18.2以降)と、遷移先で発火するpagereveal(Chrome 123・Safari 18.2以降)で遷移タイプを付与します。event.activationからは遷移元の履歴エントリ(from)と遷移先(entry)が取れるため、URLの階層を比較して方向を決められます。
function determineType(from, to) {
// クロスオリジンを含む遷移では url が無いことがある
if (!from?.url || !to?.url) return undefined;
const depth = (entry) => new URL(entry.url).pathname.split("/").filter(Boolean).length;
return depth(to) > depth(from) ? "forwards" : "backwards";
}
window.addEventListener("pageswap", (event) => {
// リダイレクト鎖にクロスオリジンURLがあると activation は null になる
if (!event.viewTransition || !event.activation) return;
const type = determineType(event.activation.from, event.activation.entry);
if (type) event.viewTransition.types.add(type);
});
window.addEventListener("pagereveal", (event) => {
if (!event.viewTransition || !navigation.activation) return;
const type = determineType(navigation.activation.from, navigation.activation.entry);
if (type) event.viewTransition.types.add(type);
});
pagereveal側でnavigation.activationを参照しているのは、遷移先ページにはevent.activationが無いためです。activationのnullチェックを入れているのは、リダイレクト鎖のどこかにクロスオリジンURLがあるとMDNの記載どおりnullが返るからです。なおこの2つのイベントはFirefoxでは発火しません。方向の出し分けが要件なら、この分岐が効かない環境でも成立する既定アニメーションを先に用意してください。
アニメーションの共通化と出し分け
view-transition-classによる複数要素の設定集約
カードが並ぶ一覧のように同じ演出を多数の要素へ適用する場面では、要素ごとに疑似要素セレクタを書くと保守できません。Chrome 125・Safari 18.2・Firefox 144以降で使えるview-transition-classを使うと、共通の指定を1つのルールに集約できます。
#card-1 {
view-transition-name: card-1;
}
#card-2 {
view-transition-name: card-2;
}
.card {
view-transition-class: card;
}
::view-transition-group(.card) {
animation-duration: 250ms;
}
ここで見落としやすいのは、クラスを付けても各要素には一意のview-transition-nameが別途必要という点です。クラスは疑似要素をまとめて選択するための仕組みであり、遷移グループを識別する役割は持ちません。名前を省いた要素は遷移の対象になりません。
transition typesによる方向別演出の切り替え
1つのページに複数の遷移パターンがある場合は、遷移タイプで演出を切り替えます。サイト全体で1種類に固定するならCSSのtypesディスクリプタ、遷移ごとに値を変えるならJavaScript側で付与する、という使い分けになります。まずCSSで固定する書き方です。
@view-transition {
navigation: auto;
types: forwards;
}
html:active-view-transition-type(forwards) {
&::view-transition-old(main-image) {
animation-name: slide-out-to-left;
}
&::view-transition-new(main-image) {
animation-name: slide-in-from-right;
}
}
同一ドキュメント遷移で動的にタイプを決めるときは、更新処理とタイプをまとめてオブジェクトで渡します。クロスドキュメント遷移で遷移ごとに変えたい場合は、前節のviewTransition.types.add()を使います。
const nextId = 2;
const transition = document.startViewTransition({
update: () => showDetail(nextId),
types: ["forwards"],
});
transition.finished.then(() => {
document.querySelector("#status").textContent = "遷移完了";
});
この形式(updateとtypesを持つオプション引数)はChrome 125・Safari 18.2・Firefox 147以降で、2026年1月13日にBaselineへ到達しました。コールバックを直接渡す旧来の呼び出し方は引き続き使えるので、タイプが不要なら書き換える必要はありません。
フレームワーク側の対応状況
クライアントサイドルーティングを持つフレームワークでは、ルータ側がこのAPIを包み込む実装が入っています。Nuxtはexperimental.viewTransitionオプションを持ち、@nuxt/schema 4.5.2 の既定値はfalseです。有効化するとクライアントルータ用のプラグインが追加されます。Astro 7.2.0はClientRouterコンポーネントを同梱し、fallbackプロパティでnone・animate・swapを選べます(既定はanimate)。未対応ブラウザでも近い演出を出したい場合、この層でのフォールバックが現実的な解になります。Next.js 16.3.0はnext/linkにtransitionTypesプロパティを持ち、ReactのaddTransitionType経由でViewTransitionコンポーネントへ遷移種別を渡す設計です。
ただし、いずれも同一ドキュメント遷移(クライアントサイドの画面差し替え)を包む層であり、Firefoxのクロスドキュメント遷移未対応を解消するものではありません。Vueで宣言的にアニメーションを書く方法はVue 3のトランジション機能の解説にまとまっています。
導入を見送るべき条件と実装の失敗パターン
このAPIは「全面的に採用する/しない」で決める種類のものではありません。同一ドキュメント遷移は入れて損がない一方、クロスドキュメント遷移は環境を選びます。次の条件に当てはまるなら、クロスドキュメント遷移の導入は見送るべきです。
- 利用者のブラウザがFirefoxに偏っている、または指定ブラウザがFirefoxである業務システム
- Firefox ESRを社内配布している環境(現行140系では同一ドキュメント遷移すら既定で無効)
- 遷移の見え方が仕様書で確定していて、環境差による差異が受け入れテストで不合格になる案件
- 遷移演出の完了を前提に後続処理を走らせる設計(可視性がhiddenのときスキップされるため成立しない)
実装後に発覚する不具合は、圧倒的にview-transition-nameの重複が多数を占めます。同時に描画されている要素で名前がぶつかると、エラーも警告も出さずに遷移だけが消えるため、原因にたどり着くまで時間を取られます。残り2つは条件付きで、いずれも見落としやすいものです。1つはbfcacheがらみで、スナップショット取得後に名前を外さないとページ状態と一緒にキャッシュへ残り、戻る操作をしたときに別の要素へ同じ名前が割り当たってやはりスキップされます。もう1つはアクセシビリティで、視差効果を減らす設定を無視すると全画面が動く演出が強制されます。後者への対処はCSS側で完結します。
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
環境判定をスクリプト側で持ちたい場合は、機能ごとに検出します。クロスドキュメント遷移の可否は@view-transitionと同時に実装されるCSSViewTransitionRuleの有無で判別できます。
const sameDocumentOK = typeof document.startViewTransition === "function";
const crossDocumentOK = typeof CSSViewTransitionRule !== "undefined";
document.documentElement.classList.toggle("has-vt", sameDocumentOK);
console.log(sameDocumentOK, crossDocumentOK);
Chrome 147以降の拡張と今後の見通し
仕様の拡張はChromiumが先行し、他ブラウザが追う流れが続いています。Chrome 147(BCD記載のリリース日は2026年4月7日、段階的ロールアウトの開始は3月25日)では、ドキュメント全体ではなく特定の要素だけを遷移させるElement.startViewTransition()とview-transition-scopeプロパティが入りました。モーダルやサイドパネルなど、画面の一部だけを差し替えるUIで全画面のスナップショットを避けられます。ただし現時点ではChromium系のみの対応で、SafariもFirefoxも未実装です。
現実的な進め方としては、同一ドキュメント遷移とview-transition-class、遷移タイプまでを本番採用の範囲とし、クロスドキュメント遷移と要素単位の遷移は「対応環境での上乗せ」に留めるのが妥当です。全ブラウザで同じ演出を保証したい要件なら、SSGOIのような画面遷移アニメーション専用ライブラリや、Anime.js v4のようなアニメーションライブラリで実装をJavaScript側に寄せる選択肢のほうが要件に合います。
よくある質問
View Transitions APIの対応ブラウザはどこまでですか?
同一ドキュメント遷移はChrome 111・Edge 111・Safari 18・Firefox 144以降で、2025年10月14日にBaselineへ到達しています。クロスドキュメント遷移はChrome 126・Edge 126・Safari 18.2以降のみで、Firefoxは未対応です。モバイル版の対応バージョンはデスクトップ版と同一です。
Firefoxでページ間の遷移アニメーションが出ないのはなぜですか?
Firefoxが@view-transitionルールを実装していないためです。実装ミスではありません。オプトインの記述は無視され、通常のページ読み込みとして処理されます。同一ページ内の遷移はFirefox 144以降であれば動きます。
SPAとMPAでコードは変わりますか?
変わります。SPAはdocument.startViewTransition()にDOM更新処理を渡すJavaScriptの実装、MPAは遷移元と遷移先の両方のCSSに@view-transitionを置くだけの実装です。疑似要素へのアニメーション指定は両者で共通に書けます。
view-transition-nameは重複しても問題ありませんか?
問題になります。同時に描画されている要素の間で値が重複すると、ViewTransition.readyがrejectされ遷移はスキップされます。遷移対象を動的に決めるUIでは、対象要素だけに名前を付け、スナップショット取得後に外してください。
未対応ブラウザではどのように表示されますか?
演出だけが省かれ、画面の内容は正しく更新されます。ただしSPAで存在チェックを書かずにdocument.startViewTransition()を呼ぶと例外が発生し、DOM更新自体が実行されません。分岐は必ず入れてください。