View Transitions APICSS動畫SPA前端開發2026

零 JS 實現流暢頁面過渡:View Transitions API 2026 實戰

View Transitions API 完整教學!80%+ 瀏覽器支援、SPA 路由過渡、Morph 動畫攻略。2026 年工程師必看的 CSS 動畫指南!

· 5 分鐘閱讀

過去要做頁面之間的流暢過渡,你需要 JavaScript 動畫庫,或者乾脆不做。Framer Motion、GSAP、React Spring——這些都是好工具,但它們的學習成本和 bundle 體積,不是每個專案都值得承擔的。View Transitions API 是瀏覽器原生支援的頁面過渡 API,2026 年 Safari 18+ 和 Firefox 133+ 的支援,讓覆蓋率突破了 80%。這不再是一個「實驗性」的功能——這是一個 production-ready 的選項。


瀏覽器支援現況

功能ChromeEdgeSafariFirefox
Same-document transitions111+111+18+133+
Cross-document transitions126+126+18.2+開發中
View Transition Groups129+129+

80%+ 的全球覆蓋率,讓 View Transitions API 成為 2026 年可以考慮用於生產環境的技術。


View Transitions API 的核心概念

View Transitions API 的設計非常聰明:它利用瀏覽器對 DOM 變化的理解,自動捕捉「之前」和「之後」的截圖,然後用 CSS 動畫過渡

頁面點擊 → DOM 更新 → 瀏覽器截圖「之前」和「之後」狀態
→ CSS 動畫過渡 → 完成

對前端工程師來說,你只需要:

  1. 包裹你的 DOM 變化邏輯
  2. 寫 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 APIFramer 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 把這個效果的門檻降到了零。


延伸閱讀

本文是「2026 CSS 實用技術」系列文章之一。