Next.js動畫CSS和佈局

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>
<ViewTransition
enter={{ "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,你聲明連接兩個狀態的東西,讓瀏覽器從兩張照片繪製連接。