📋 目錄
過去要做頁面之間的流暢過渡,你需要 JavaScript 動畫庫,或者乾脆不做。Framer Motion、GSAP、React Spring——這些都是好工具,但它們的學習成本和 bundle 體積,不是每個專案都值得承擔的。View Transitions API 是瀏覽器原生支援的頁面過渡 API,2026 年 Safari 18+ 和 Firefox 133+ 的支援,讓覆蓋率突破了 80%。這不再是一個「實驗性」的功能——這是一個 production-ready 的選項。
瀏覽器支援現況
| 功能 | Chrome | Edge | Safari | Firefox |
|---|---|---|---|---|
| Same-document transitions | 111+ | 111+ | 18+ | 133+ |
| Cross-document transitions | 126+ | 126+ | 18.2+ | 開發中 |
| View Transition Groups | 129+ | 129+ | ❌ | ❌ |
80%+ 的全球覆蓋率,讓 View Transitions API 成為 2026 年可以考慮用於生產環境的技術。
View Transitions API 的核心概念
View Transitions API 的設計非常聰明:它利用瀏覽器對 DOM 變化的理解,自動捕捉「之前」和「之後」的截圖,然後用 CSS 動畫過渡。
頁面點擊 → DOM 更新 → 瀏覽器截圖「之前」和「之後」狀態
→ CSS 動畫過渡 → 完成
對前端工程師來說,你只需要:
- 包裹你的 DOM 變化邏輯
- 寫 CSS 來定義動畫效果
基礎語法
JavaScript API
// 最基礎的用法:包裹任何 DOM 變化
async function navigateTo(page) {
if (!document.startViewTransition) {
// 不支援的瀏覽器:直接更新
await updateDOM(page);
return;
}
// document.startViewTransition 會自動截圖並執行過渡
await document.startViewTransition(async () => {
await updateDOM(page);
}).finished;
}
CSS 動畫控制
/* 預設過渡:簡單的交叉淡化 */
@keyframes fade-in {
from { opacity: 0; }
}
@keyframes fade-out {
to { opacity: 0; }
}
::view-transition-old(root) {
animation: 300ms ease-out fade-out;
}
::view-transition-new(root) {
animation: 300ms ease-out fade-in;
}
自訂過渡動畫
/* 滑動過渡 */
::view-transition-old(root) {
animation: slide-out 300ms ease-out forwards;
}
::view-transition-new(root) {
animation: slide-in 300ms ease-out forwards;
}
@keyframes slide-out {
to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in {
from { transform: translateX(100%); opacity: 0; }
}
實際應用場景
1. SPA 路由過渡
React Router 或 Vue Router 整合:
// React Router v7 / Remix
import { useNavigate } from 'react-router';
function App() {
const navigate = useNavigate();
const handleNav = async (path) => {
await document.startViewTransition(() => {
navigate(path);
}).finished;
};
return (
<nav>
<button onClick={() => handleNav('/about')}>About</button>
<button onClick={() => handleNav('/contact')}>Contact</button>
</nav>
);
}
/* 路由過渡動畫 */
::view-transition-old(root) {
animation: slide-out 250ms ease-out forwards;
}
::view-transition-new(root) {
animation: slide-in 300ms ease-out forwards;
}
@keyframes slide-out {
to { transform: translateX(-30px); opacity: 0; }
}
@keyframes slide-in {
from { transform: translateX(30px); opacity: 0; }
}
2. 元素 Morph 動畫(卡片展開詳情)
這是 View Transitions API 最令人驚艷的功能:元素可以從一個位置「變形」到另一個位置,而不只是整頁的淡化。
// 給要對應的元素一個唯一的名稱
function openCard(cardData) {
document.startViewTransition(() => {
// 渲染詳情視圖
renderDetail(cardData);
});
}
/* 設定元素的 view-transition-name */
.card {
view-transition-name: card-item;
}
/* 詳情頁面中的對應元素 */
.detail-view {
view-transition-name: card-item;
}
/* 這樣瀏覽器會自動動畫:卡片 → 詳情視圖的過渡 */
/* 自訂這個特定元素的過渡動畫(不影響其他元素) */
::view-transition-old(card-item) {
animation: card-shrink 300ms ease-in-out forwards;
}
::view-transition-new(card-item) {
animation: card-expand 400ms ease-in-out forwards;
}
@keyframes card-shrink {
to {
border-radius: 8px;
transform: scale(0.8);
}
}
@keyframes card-expand {
from {
border-radius: 8px;
transform: scale(0.8);
}
}
3. 圖片放大效果
Instagram/FB 那種點擊圖片後放大到全屏的效果:
function openImage(imageSrc) {
// 圖片已經有 view-transition-name
document.startViewTransition(() => {
renderFullscreenImage(imageSrc);
});
}
/* 縮圖 */
.thumbnail {
view-transition-name: fullscreen-image;
border-radius: 8px;
}
/* 全屏顯示 */
.fullscreen-image {
view-transition-name: fullscreen-image;
border-radius: 0; /* 過渡時會動畫這個屬性 */
position: fixed;
inset: 0;
}
4. 列表到詳情的過渡
// 點擊列表中的項目
document.startViewTransition(() => {
// 隱藏列表,顯示詳情
list.style.display = 'none';
detail.style.display = 'block';
// 填充詳情資料
renderDetail(data);
});
/* 列表項目的過渡 */
.list-item {
view-transition-name: list-to-detail;
}
.detail {
view-transition-name: list-to-detail;
}
::view-transition-old(list-to-detail) {
animation: list-shrink 200ms ease-out forwards;
}
::view-transition-new(list-to-detail) {
animation: detail-expand 350ms ease-out forwards;
}
與 Framer Motion 的比較
| 維度 | View Transitions API | Framer Motion |
|---|---|---|
| Bundle 體積 | 0KB | ~60KB |
| 主執行緒 | 外(瀏覽器 paint) | 主執行緒(JavaScript) |
| 瀏覽器支援 | ~80% | 100% |
| 動畫複雜度 | 簡單到中等 | 極高 |
| DOM 變化處理 | 原生 | 需手動處理 |
| 學習成本 | 低 | 中 |
View Transitions API 勝出的場景
- 頁面/路由之間的簡單過渡
- 列表到詳情的標準過渡
- 圖片放大/縮小
- 任何「前後狀態明確」的 DOM 變化
Framer Motion 仍然必要的場景
- 拖拽交互(drag)
- 手勢動畫(swipe、pinch)
- 複雜的狀態動畫(spring physics)
- 滾動連動動畫(Scroll-linked)
Next.js App Router 原生支援
Next.js App Router 從 14 開始實驗性支援 View Transitions,15+ 更加穩定:
// app/layout.tsx
import { ViewTransition } from 'next-view-transition';
export default function Layout({ children }) {
return (
<html>
<body>
<ViewTransition>{children}</ViewTransition>
</body>
</html>
);
}
// app/page.tsx
import Link from 'next/link';
export default function Home() {
return (
<Link href="/about" viewTransition>
Go to About
</Link>
);
}
無障礙支援
View Transitions API 的一大優勢是瀏覽器原生支援無障礙:
prefers-reduced-motion:用戶選擇減少動畫時,API 會自動跳過或簡化過渡- ARIA 支援:視覺過渡的同時,ARIA 狀態同步更新
- Focus 管理:自動確保焦點在過渡後的正確位置
/* 尊重用戶的無障礙設置 */
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
}
結語:現在就可以開始用
View Transitions API 在 2026 年的支援率已經足夠用於生產環境。對於 SPA 應用中的頁面過渡、列表到詳情的過渡、圖片放大效果,View Transitions API 提供了一個零依賴、效能優秀、原生無障礙支援的解決方案。
對於已經在使用 Framer Motion 的專案,不需要急著替換——Framer Motion 的動畫表現力遠超 View Transitions API。但如果你的專案本來就沒有複雜的動畫需求,只是想要「讓頁面過渡看起來不那麼生硬」,View Transitions API 是更好的選擇。
從「生硬的頁面跳轉」到「流暢的視覺過渡」,View Transitions API 把這個效果的門檻降到了零。
延伸閱讀
- Interop 2026 瀏覽器大一統 — 瀏覽器相容性狀態
- CSS Nesting vs Sass — CSS 工具比較
本文是「2026 CSS 實用技術」系列文章之一。