View Transitions 與 Next.js:無需函式庫的頁面動畫
View Transitions 與 Next.js:無需函式庫的頁面動畫
View Transitions API 從你手中奪走那個技巧,交給瀏覽器。瀏覽器不再保持兩個活躍的 DOM 樹並進行測量,而是拍下舊狀態的快照,讓 DOM 更新,拍下新狀態的快照,然後在兩張圖片之間進行動畫——在合成器上。
javascript
function navigate(update) {if (!document.startViewTransition) {update(); // 不支援:只是更新,無動畫return;}document.startViewTransition(() => update());}
css
::view-transition /* 覆蓋整個頁面的疊加層 */::view-transition-group(name) /* 動畫化大小和位置 */::view-transition-image-pair(name)::view-transition-old(name) /* "之前"的快照 */::view-transition-new(name) /* "之後"的快照 */
讓所有人驚訝的事:快照是照片,不是元素
::view-transition-old 不是你的舊元素縮小後的樣子。它是一張靜態圖片。<video> 會凍結在某一幀。載入旋轉器會停止旋轉。在 200ms 時,這無關緊要。在 1000ms 時,一切都變得顯而易見。
命名:整個合約
css
.card-image {view-transition-name: hero;}::view-transition-group(hero) {animation-duration: 400ms;animation-timing-function: ease-in-out;}
嚴格規則:view-transition-name 在任何時刻都必須在文件中唯一。
React 19.2 與 Next.js 16:一個元件
tsx
import { ViewTransition } from "react";import Image from "next/image";import Link from "next/link";export function ProjectCard({ project }) {return (<Link href={"/projects/" + project.slug}><ViewTransition name={"project-" + project.slug}><Image src={project.cover} alt={project.title} /></ViewTransition></Link>);}
share 和 default="none" 必須一起使用。使用 default="none" 而沒有 share prop 時,命名對會悄悄停止變形。
方向:告訴使用者他們往哪個方向前進
tsx
<Link href="/projects/runvalis" transitionTypes={["nav-forward"]}>Runvalis</Link><ViewTransitionenter={{ "nav-forward": "slide-in", "nav-back": "slide-out", default: "none" }}exit={{ "nav-forward": "slide-out", "nav-back": "slide-in", default: "none" }}default="none"><main>{children}</main></ViewTransition>
無框架版本
css
@view-transition {navigation: auto;}
陷阱與最佳實踐
- 始終視為漸進增強。
- 用慢動作除錯。
- 尊重
prefers-reduced-motion。 - 疊加層預設會吞掉點擊。
- 快照消耗記憶體。
- 錨定標頭。
- 視圖轉換對輔助技術不可見。
總結
View Transitions 是應用於導航的相同論點:不再手動執行 FLIP,你聲明連接兩個狀態的東西,讓瀏覽器從兩張照片繪製連接。