CSS Cross-Document View Transitions:MPA 多頁應用也能做絲滑頁面過渡動畫
什麼是 Cross-Document View Transitions
你有沒有注意到,用 SPA 框架做的網站在切換頁面時可以有很流暢的動畫過渡,但傳統的多頁應用(MPA)一點擊連結就硬生生地整頁重載?這個體驗落差一直是前端開發者的痛點。
CSS Cross-Document View Transitions 就是來解決這個問題的。它是 View Transitions API 的延伸,讓瀏覽器在跨頁面導航時也能自動產生過渡動畫。最厲害的是,你只需要幾行 CSS 就能啟用,完全不需要寫任何 JavaScript。
如果你已經熟悉同頁面的 View Transitions,可以參考 View Transitions API 基礎教學,Cross-Document 版本是它的自然延伸。
SPA vs MPA:動畫體驗的鴻溝
先來聊聊為什麼這個功能這麼重要。長久以來,SPA 和 MPA 在使用者體驗上有個巨大的鴻溝:
SPA 的優勢:頁面切換時不需要整頁重載,可以做出流暢的過渡動畫,使用者感覺像在用 App。但代價是需要引入 React、Vue 等框架,打包體積大,SEO 處理複雜。
MPA 的優勢:架構簡單、SEO 友善、首次載入快。但每次點連結都是硬切頁面,沒有任何過渡效果,體驗感覺很「網頁」。
Cross-Document View Transitions 直接抹平了這個差距。你可以保留 MPA 的所有優點,同時獲得 SPA 等級的過渡動畫。這對於用 Next.js、Astro、甚至純 HTML 做的網站來說,都是巨大的體驗升級。
基本設定:@view-transition 規則
啟用 Cross-Document View Transitions 的方式簡單到不可思議。你只需要在 CSS 裡加上一個 at-rule:
@view-transition {
navigation: auto;
}沒錯,就這一行。把這段 CSS 加到你的全站樣式裡,瀏覽器就會自動在同源(same-origin)的頁面導航時套用預設的淡入淡出過渡效果。
要注意的是,navigation: auto 只對同源導航有效,也就是說只有在同一個網域內的頁面切換才會觸發。跨域導航不會套用過渡動畫,這是基於安全考量。
預設的過渡效果是整頁的 cross-fade(交叉淡化),看起來大概像是舊頁面淡出、新頁面淡入的感覺。雖然簡單,但比硬切頁面已經好太多了。
自訂過渡動畫效果
預設的 cross-fade 不夠炫?沒問題,你可以用 ::view-transition 偽元素系列來完全自訂過渡動畫。
View Transitions 的動畫架構是這樣的:瀏覽器會在導航時建立一個過渡層,裡面有舊頁面的截圖(::view-transition-old)和新頁面的即時畫面(::view-transition-new)。你可以分別對這兩個偽元素設定 CSS 動畫。
::view-transition-old(root) {
animation: slide-out 0.3s ease-in;
}
::view-transition-new(root) {
animation: slide-in 0.3s ease-out;
}
@keyframes slide-out {
to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in {
from { transform: translateX(100%); opacity: 0; }
}上面的範例會產生「舊頁面向左滑出、新頁面從右滑入」的效果,跟很多原生 App 的導航動畫一模一樣。
你也可以用不同的 timing function 來調整動畫的節奏感。我個人很喜歡用 cubic-bezier(0.4, 0, 0.2, 1),這是 Material Design 的標準 easing,動畫起來很自然。
view-transition-name 元素級控制
整頁過渡已經很棒了,但 Cross-Document View Transitions 真正強大的地方在於元素級的過渡控制。透過 view-transition-name 屬性,你可以讓特定元素在頁面切換時「無縫移動」到新位置。
/* 列表頁的文章卡片 */
.article-card {
view-transition-name: article-hero;
}
/* 文章頁的 hero image */
.article-hero-image {
view-transition-name: article-hero;
}當使用者從列表頁點進文章頁時,瀏覽器會辨識出兩邊有相同 view-transition-name 的元素,然後自動產生一個從卡片位置「飛」到 hero image 位置的動畫。這個效果在 Material Design 裡叫做「shared element transition」,以前只有原生 App 才做得到。
有幾個重要的限制要注意:
- 同一個頁面裡,每個
view-transition-name的值必須是唯一的 - 名稱不能是
none(這是保留值,用來取消過渡) - 動態生成的名稱要確保在兩個頁面之間能對應上
搭配之前介紹過的 CSS Scroll-Driven Animations 教學,你可以打造出非常豐富的動態體驗。
瀏覽器支援與漸進增強
截至 2026 年初,Cross-Document View Transitions 的瀏覽器支援狀況:
- Chrome 126+:完整支援(2024 年 6 月起)
- Edge 126+:完整支援(跟 Chrome 同步)
- Safari:透過 Interop 2026 計畫開發中,預計 Safari 20 支援
- Firefox:同樣在 Interop 2026 計畫中,預計 2026 下半年支援
好消息是,這個功能天生就是漸進增強的。不支援的瀏覽器會直接忽略 @view-transition 規則和 view-transition-name 屬性,頁面導航還是照常運作,只是沒有過渡動畫而已。完全不會影響功能。
你也可以用 @supports 來做更精細的控制:
@supports (view-transition-name: none) {
/* 有支援時才載入過渡動畫相關的樣式 */
}實戰範例:部落格頁面過渡
來看一個完整的部落格實作範例。假設你有一個文章列表頁和文章內容頁,想要實現:列表頁到文章頁的淡入滑動效果,以及文章封面圖的 shared element transition。
首先在全站 CSS 加上基本設定:
@view-transition {
navigation: auto;
}
::view-transition-old(root) {
animation: fade-and-scale-out 0.25s ease-in;
}
::view-transition-new(root) {
animation: fade-and-scale-in 0.25s ease-out;
}
@keyframes fade-and-scale-out {
to { opacity: 0; transform: scale(0.95); }
}
@keyframes fade-and-scale-in {
from { opacity: 0; transform: scale(1.05); }
}然後對文章封面圖加上元素級過渡。在列表頁的 HTML 裡,每張卡片封面都給一個動態的 view-transition-name:
<img class="card-cover" style="view-transition-name: cover-post-123" />在文章頁的 hero image 上用同樣的名稱:
<img class="hero-image" style="view-transition-name: cover-post-123" />這樣當使用者點擊卡片時,封面圖會「飛」到文章頁的 hero 位置,背景則做一個淡入淡出。整個效果只用了 CSS,零 JavaScript。搭配 CSS :has() 選擇器進階教學 裡的技巧,你可以做出更多互動效果。
結語
CSS Cross-Document View Transitions 是我今年看到最讓我興奮的前端功能之一。它真正做到了「用最少的程式碼達到最大的體驗提升」這件事。以前要做這種效果,你需要搬出 React + Framer Motion 或者 GSAP 這種重量級工具,現在只要幾行 CSS 就搞定。
對於部落格、電商、作品集這類以內容為主的網站來說,這個功能帶來的體驗提升是立竿見影的。而且因為是純 CSS 實現,對效能幾乎零影響。
我的建議是現在就開始在專案裡加上 @view-transition { navigation: auto; } 這一行,讓支援的瀏覽器立刻享受到過渡效果,同時等待其他瀏覽器跟進。漸進增強,穩穩地提升使用者體驗。
繼續閱讀
CSS Masonry 瀑布流原生佈局教學:不靠 JavaScript 也能做出 Pinterest 排版
CSS Masonry Layout 終於原生支援了!這篇教學帶你用純 CSS 實作瀑布流排版,不再需要 Masonry.js 或其他套件。
相關文章
你可能也喜歡
探索其他領域的精選好文