📋 目錄
過去要實現頁面之間的流暢過渡動畫,工程師必須引入 Framer Motion、GSAP 這類 JavaScript 動畫庫。2025 年 10 月,CSS View Transitions 達到 Baseline(Baseline Newly Available),代表這項技術已經獲得所有主流瀏覽器的穩定支援。本文整理 View Transitions 的完整用法,讓你不需要任何額外依賴,就能做出流暢的頁面過渡效果。
為什麼前端工程師要關心 View Transitions
做過 SPA(Single Page Application)路由過渡動畫的工程師,都知道這件事有多麻煩:你要在每個頁面切換的時機點捕捉 DOM 狀態、計算動畫、執行過渡,還要處理返回(back navigation)的情境。
傳統解法有兩種:
-
JavaScript 動畫庫(Framer Motion、GSAP):功能強大,但需要維護一個不小的 runtime,且你要自己處理「什麼時候觸發動畫」這件事。
-
CSS Animation + class toggle:看起來簡單,但做起來複雜——你需要在路由層級自己計算新舊頁面的相對位置,计算 cross-fade 的時機。
View Transitions 的價值在於:瀏覽器自己處理了這一切。瀏覽器知道什麼時候頁面要切換、知道新舊狀態的快照(snapshot)、知道怎麼做 cross-fade。你只需要一行 API 呼叫。
View Transitions 的兩種類型
Same-Document:單一頁面內的狀態過渡
適用於 SPA 的路由切換、動態內容替換等場景。
// 觸發 Same-Document View Transition
document.startViewTransition(() => {
// 在這個 callback 裡執行 DOM 更新
// 瀏覽器會自動為更新前後的 DOM 建立快照,
// 並在兩者之間執行 cross-fade 或自訂動畫
updateDOM();
});
<!DOCTYPE html>
<html>
<head>
<style>
/* View Transition 的預設 cross-fade 動畫 */
::view-transition-old(root) {
animation: 200ms ease-out fade-out;
}
::view-transition-new(root) {
animation: 200ms ease-in fade-in;
}
/* 如果你想控制整個頁面的過渡 */
.view-transition-page {
animation: 300ms ease both slide-from-right;
}
</style>
</head>
<body>
<nav>
<a href="/home" onclick="navigate(event)">Home</a>
<a href="/about" onclick="navigate(event)">About</a>
</nav>
<main id="content"></main>
<script>
async function navigate(event) {
event.preventDefault();
const href = event.currentTarget.getAttribute('href');
await document.startViewTransition(async () => {
// 更新 DOM
const page = await fetchPage(href);
document.getElementById('content').innerHTML = page;
// 更新 URL
history.pushState({}, '', href);
});
}
</script>
</body>
</html>
Cross-Document:頁面之間的過渡
適用於 MPA(Multi-Page Application),不同 HTML 文件之間的過渡。
<!-- page-a.html -->
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<!-- 重要:宣告同一個 origin 內的跨文件過渡 -->
<meta name="view-transition" content="same-origin" />
</head>
<body>
<header>
<nav>
<!-- 連結到同一 origin 內的其他頁面,會自動觸發 View Transition -->
<a href="page-b.html">前往 B 頁面</a>
</nav>
</header>
</body>
</html>
<!-- page-b.html -->
<!DOCTYPE html>
<html lang="zh-TW">
<head>
<meta name="view-transition" content="same-origin" />
<style>
/* 定義過渡動畫 */
::view-transition-old(root) {
animation: 250ms cubic-bezier(0.4, 0, 0.2, 1) both fade-out,
250ms cubic-bezier(0.4, 0, 0.2, 1) 30ms both slide-to-left;
}
::view-transition-new(root) {
animation: 300ms cubic-bezier(0, 0, 0.2, 1) 100ms both fade-in,
300ms cubic-bezier(0, 0, 0.2, 1) 100ms both slide-from-right;
}
</style>
</head>
<body>
<header>
<nav>
<a href="page-a.html">返回 A 頁面</a>
</nav>
</header>
</body>
</html>
關鍵:view-transition meta 標籤
這行 HTML 告訴瀏覽器:同一個 origin 內的 <a href> 連結點擊時,應該觸發 Cross-Document View Transition。不需要 JavaScript。
進階自訂:::view-transition-old 與 ::view-transition-new
預設的 cross-fade 適合大多數場景,但你可以透過 CSS 完全自訂過渡動畫。
自訂整頁過渡
/* 自訂滑動過渡 */
@keyframes slide-out-to-left {
from { transform: translateX(0); opacity: 1; }
to { transform: translateX(-30px); opacity: 0; }
}
@keyframes slide-in-from-right {
from { transform: translateX(30px); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
::view-transition-old(root) {
animation: 200ms ease-out slide-out-to-left;
}
::view-transition-new(root) {
animation: 200ms ease-in slide-in-from-right;
}
自訂特定元素的過渡(Element Transition)
View Transitions 最強大的功能之一:可以對特定元素定義專屬過渡動畫,而其他元素執行不同的過渡。
// 當某個產品卡被點擊時,
// 讓這張圖片執行「放大並移動到目標位置」的過渡
// 同時其他內容執行 cross-fade
document.startViewTransition(async () => {
// 1. 為即將執行的圖片過渡命名
const heroImage = document.querySelector('.product-card__image');
// 2. 在 DOM 更新前,先標記這個元素
if (heroImage) {
heroImage.style.viewTransitionName = 'product-hero';
}
// 3. 執行 DOM 更新
await fetchAndRenderProductPage(productId);
});
/* 圖片自己的過渡動畫:從小卡片位置過渡到全尺寸 */
::view-transition-old(product-hero) {
animation: 300ms ease-out scale-down-to-normal;
}
::view-transition-new(product-hero) {
animation: 300ms ease-out scale-up-from-small;
}
/* 其他元素執行預設過渡 */
::view-transition-old(root),
::view-transition-new(root) {
animation: 200ms ease-out fade-out/fade-in;
}
實際應用場景:電子商務產品頁
電子商務網站的「從列表頁點擊商品,圖片放大過渡到詳情頁」是 View Transitions 最典型的應用場景:
// product-list.js
function handleProductClick(productId, imageElement) {
// 為即將點擊的圖片設定 view-transition-name
imageElement.style.viewTransitionName = `product-${productId}`;
document.startViewTransition(async () => {
// 移除 transition name,避免干擾
imageElement.style.viewTransitionName = '';
// 導航到詳情頁
await navigateToProduct(productId);
});
}
/* product-detail.css */
/* 圖片會從列表中的小尺寸,漸變為詳情頁的大尺寸 */
::view-transition-old(product-\d+) {
animation: none;
mix-blend-mode: normal;
}
::view-transition-new(product-\d+) {
animation: none;
mix-blend-mode: normal;
}
瀏覽器支援(2026 年 3 月)
| 類型 | Chrome/Edge | Safari | Firefox |
|---|---|---|---|
| Same-Document | ✅ 111+ | ✅ 18+ | ✅ 133+ |
| Cross-Document | ✅ 126+ | ✅ 18.2+ | 🔄 開發中 |
| view-transition meta | ✅ 126+ | ✅ 18.2+ | 🔄 開發中 |
Baseline 狀態:Same-document View Transitions 於 2025 年 10 月達到 Baseline(表示所有主流瀏覽器都已經穩定支援)。
Cross-Document 的 Firefox 支援仍在開發中,如果你的用戶有很大比例是 Firefox 使用者,你需要提供 fallback。
Feature Detection
// 檢查瀏覽器是否支援 View Transitions
if (!document.startViewTransition) {
// Fallback:直接執行導航,不做過渡動畫
navigateWithoutTransition();
return;
}
// 支援:執行過渡動畫
await document.startViewTransition(() => navigate());
<!-- Cross-document 的 fallback: Progressive Enhancement -->
<!-- 在 Firefox 上,連結會正常跳轉,不會有 View Transition -->
<a href="/page-b.html" view-transition="same-origin">
前往 B 頁面
</a>
與 JavaScript 動畫庫的比較
| 維度 | View Transitions | Framer Motion | GSAP |
|---|---|---|---|
| 學習曲線 | 低 | 中 | 高 |
| 依賴大小 | 0(瀏覽器原生) | ~30KB | ~60KB |
| 頁面間過渡 | ✅ 原生支援 | ❌ 需要自行處理 | ❌ 需要自行處理 |
| 效能 | 瀏覽器原生優化 | 優秀 | 優秀 |
| 控制粒度 | 中等 | 細緻 | 極細緻 |
| 複雜動畫(如 FLIP) | 受限 | 完全支援 | 完全支援 |
結論:
- 簡單到中等的過渡 → View Transitions(首選)
- 需要複雜 choreography、FLIP 動畫、手勢驅動 → Framer Motion 或 GSAP
- 兩者也可以結合:View Transitions 處理頁面過渡,JS 庫處理頁面內的複雜動畫
實務建議:從哪里開始
立即可以在專案使用的場景
-
SPA 路由過渡(Same-document)
- Next.js、React Router、Vue Router 都可以整合
- 最簡單的實作:在路由切換時包一層
document.startViewTransition
-
返回按鈕的過渡一致性
- 過去返回時的動畫方向是個大麻煩
- View Transitions 自動為 forward/back 導航提供不同的過渡方向
-
電子商務產品頁過渡
- 「列表 → 詳情」的圖片放大效果,是 View Transitions 的旗艦級應用
整合到 React(Next.js App Router)
// app/page.tsx
'use client';
import { useRouter } from 'next/navigation';
export function ProductCard({ product }) {
const router = useRouter();
async function handleClick() {
if (!document.startViewTransition) {
router.push(`/products/${product.id}`);
return;
}
await document.startViewTransition(async () => {
router.push(`/products/${product.id}`);
});
}
return (
<button onClick={handleClick}>
<img
src={product.image}
alt={product.name}
style={{ viewTransitionName: `product-${product.id}` }}
/>
</button>
);
}
結語
View Transitions 的核心價值不是「讓你有更多動畫選項」,而是把本來需要你自己處理的頁面過渡邏輯,交給瀏覽器來處理。
這個設計讓路由過渡從「需要工程師自己處理的事情」,變成「瀏覽器本身就知道怎麼做的預設行為」。如果你在做 SPA,而且你的用戶主要用 Chrome 或 Safari,View Transitions 現在就已經是生產就緒的選擇。
如果你需要更複雜的動畫(手勢、多物件 choreography),Framer Motion 和 GSAP 仍然是首選。但對於「滑動 cross-fade」、「從列表到詳情的圖片過渡」這類常見模式,View Transitions 已經足夠,而且零依賴。
延伸閱讀
- Interop 2026 CSS 新特性全景 — CSS 新功能的完整瀏覽器支援狀態
- CSS Scroll-Driven Animations 實戰 — 另一個原生 CSS 動畫新技術
本文是「2026 CSS 新技術」系列文章之一。