ブラウザの「裏切り」を味方につける:View Transitions API の深淵
フロントエンドエンジニア諸君、日々DOMの操作やレンダリングパイプラインとの格闘、お疲れ様。
「画面遷移を滑らかにしたい」という願いは、Web開発の黎明期から続く終わりのない旅だ。これまでは、必死にCSSアニメーションを書き、スクリプトでDOMを出し分け、ブラウザの再描画(Repaint)のタイミングを睨みながら最適化を繰り返してきたはずだ。
だが、モダンブラウザはついに、その「レンダリングの重い処理」をOSレベルのグラフィックス処理へと昇華させるView Transitions APIという最強の武器を授けてくれた。今日は、これがブラウザの内部で一体どう動いているのか、その「泥臭い真実」を紐解いていこう。
—
1. そもそもレンダリングパイプラインで何が起きているのか?
View Transitions APIが革新的なのは、従来の「DOMを書き換えてからCSSでアニメーションさせる」という手順を、「ブラウザ自身が現在の画面を静止画としてキャプチャし、次の画面までのつなぎをGPUのメモリ上でテクスチャとして合成する」というプロセスに差し替えた点にある。
通常の遷移では、DOMの入れ替えが起きるとブラウザは「Layout(再配置)」と「Paint(描画)」を強制的に行い、前のUIが一瞬消えて新しいUIが描画される。この「一瞬の空白」こそが、ユーザーにとっての「カクつき」だ。
View Transitions API (`document.startViewTransition`) を呼んだ瞬間、ブラウザは以下の処理をシームレスに行う。
1. スナップショットの取得: 現在のDOMツリーをレイヤーとしてGPUに送る。
2. DOM更新の待機: コールバック関数内のDOM変更を待つ。
3. 遷移準備: 新旧の画面の「差分」を仮想的な要素(`::view-transition-group`)としてツリーに配置する。
4. クロスフェード/アニメーション: GPU側でテクスチャとして描画し、アニメーションを実行する。
つまり、DOMの再計算のコストを、CSSのコンポジット(合成)フェーズへ逃がしているわけだ。賢いだろう?
—
2. 実践:SPA遷移での実装パターン
理屈だけでは飯は食えない。現場で即座に使える、最も標準的なSPA遷移のコードを提示しよう。Routerのフックに仕込むイメージだ。
/
- ページ遷移をView Transitions APIでラップする
- @param {Function} updateDOM – DOMを更新する関数(ReactのsetStateやinnerHTMLの書き換えなど)
/
async function transitionView(updateDOM) {
// ブラウザがAPIをサポートしているかチェック
if (!document.startViewTransition) {
await updateDOM();
return;
}
// 遷移を開始する
const transition = document.startViewTransition(async () => {
// この中でDOMの書き換えを行う
// ここが完了した瞬間に、ブラウザは「遷移先」の状態をキャプチャする
await updateDOM();
});
// 遷移が終わった後の処理が必要ならここに書く
try {
await transition.finished;
console.log(‘遷移アニメーション完了!’);
} catch (e) {
console.error(‘遷移に失敗しました’, e);
}
}
—
3. 実務でハマる「レンダリングの罠」とTips
現場で実装すると必ずぶつかる壁がある。プロとして覚えておくべきTipsを2つ共有する。
Tip 1: `view-transition-name` は「ユニーク」であれ
CSSで各要素に `view-transition-name: hero-image;` のように名前を付けることで、ブラウザは「あ、これとこれは同じ要素だから、位置を補完してアニメーションさせよう」と判断する。
ここで最も多いミスが、複数の要素に同じ名前を付けてしまうことだ。これを行うとブラウザは「どれを追跡すればいいかわからない」とパニックを起こし、遷移が無視されるか、意図しないレイアウト崩れを引き起こす。名前は常に一意であること。
Tip 2: 擬似要素を使いこなす
ブラウザが生成するツリーは以下のようになっている。
::view-transition
::view-transition-group(root)
::view-transition-image-pair(root)
::view-transition-old(root)
::view-transition-new(root)
もし、特定の要素だけを滑らかに動かしたいなら、その要素を `view-transition-name` で特定し、個別のCSSを当てればいい。例えば、ヘッダーのロゴだけを固定して、コンテンツだけをクロスフェードさせる、なんて芸当も容易だ。
/ ロゴには専用の名前を付ける /
.site-logo {
view-transition-name: site-logo;
}
/ 遷移中の旧ロゴと新ロゴの動きを個別に定義できる /
::view-transition-old(site-logo) {
animation: fade-out 0.3s;
}
—
最後に:なぜこれを使うのか
View Transitions APIは、単なる「見た目の装飾」ではない。ブラウザが内部的に持っているレンダリングパイプラインの制御権を、我々開発者が少しだけ手元に引き寄せられるようになったという「歴史的転換」なんだ。
ユーザー体験(UX)において、滑らかな遷移は「アプリの品質」と直結する。泥臭いDOM操作から解放され、より本質的な「何を見せるか」という設計に集中できる時代が来た。
もし君のチームで「画面遷移が重い」という不満が聞こえてきたら、まずはこのAPIの導入を検討してみてくれ。ブラウザの仕組みを知り尽くせば、コードはもっとエレガントになるはずだ。
また現場で会おう。健闘を祈る。

コメント