CSS View Transitions API 实战
View Transitions API 让页面切换有了原生动画支持,2024 年已经可以在主流浏览器使用。
基本概念
View Transitions API 通过截图旧状态、过渡到新状态,实现平滑的页面切换。
// 最简单的用法
document.startViewTransition(() => {
// 更新 DOM
updateContent();
});
浏览器会:
- 捕获当前页面状态
- 执行回调函数更新 DOM
- 捕获新状态
- 在两个状态间做动画
页面切换动画
// SPA 路由切换
async function navigate(url) {
if (!document.startViewTransition) {
location.href = url;
return;
}
const transition = document.startViewTransition(async () => {
const html = await fetch(url).then(r => r.text());
document.body.innerHTML = html;
});
await transition.finished;
}
// 添加 CSS 定义过渡效果
/* 默认过渡动画 */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.3s;
}
/* 自定义动画 */
::view-transition-old(root) {
animation: fade-out 0.3s ease-out;
}
::view-transition-new(root) {
animation: fade-in 0.3s ease-in;
}
@keyframes fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
元素过渡
给元素添加 view-transition-name,实现跨页面的共享元素动画:
<!-- 列表页 -->
<div class="card" style="view-transition-name: card-1">
<img src="photo.jpg" />
</div>
<!-- 详情页 -->
<div class="detail" style="view-transition-name: card-1">
<img src="photo.jpg" />
</div>
::view-transition-old(card-1),
::view-transition-new(card-1) {
animation-duration: 0.5s;
animation-timing-function: ease-in-out;
}
列表页的卡片会平滑过渡到详情页。
列表项过渡
// 删除列表项
function removeItem(id) {
document.startViewTransition(() => {
const item = document.getElementById(id);
item.remove();
});
}
// 添加列表项
function addItem(data) {
document.startViewTransition(() => {
const list = document.querySelector('.list');
const item = createItem(data);
list.appendChild(item);
});
}
/* 列表项过渡 */
.list-item {
view-transition-name: var(--item-id);
}
::view-transition-old(*) {
animation: slide-out 0.3s;
}
::view-transition-new(*) {
animation: slide-in 0.3s;
}
@keyframes slide-out {
to {
opacity: 0;
transform: translateX(-100%);
}
}
@keyframes slide-in {
from {
opacity: 0;
transform: translateX(100%);
}
}
与框架集成
React 示例:
import { useTransition } from 'react';
function useViewTransition() {
const startTransition = useTransition()[1];
return (callback) => {
if (!document.startViewTransition) {
callback();
return;
}
document.startViewTransition(() => {
startTransition(() => {
callback();
});
});
};
}
// 使用
function Card({ id }) {
const transition = useViewTransition();
return (
<div
style={{ viewTransitionName: `card-${id}` }}
onClick={() => transition(() => navigate(`/detail/${id}`))}
>
...
</div>
);
}
Next.js 集成:
// app/layout.tsx
import { ViewTransitions } from 'next-view-transitions';
export default function RootLayout({ children }) {
return (
<html>
<head>
<ViewTransitions />
</head>
<body>{children}</body>
</html>
);
}
浏览器支持
| 浏览器 | 版本 |
|---|---|
| Chrome | 111+ |
| Edge | 111+ |
| Safari | 18+ |
| Firefox | 实验性 |
兼容性处理:
function safeTransition(callback) {
if (document.startViewTransition) {
document.startViewTransition(callback);
} else {
callback();
}
}
性能注意
- 过渡元素不要太多(建议 < 50 个)
- 复杂动画会增加内存占用
- 低端设备可能需要降级
// 检测用户偏好
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
// 禁用或简化动画
updateDirectly();
} else {
document.startViewTransition(() => updateDirectly());
}
小结
View Transitions API 让页面切换动画变得简单:
- 原生支持,无需库
- 共享元素过渡效果
- 与框架集成方便
- 注意兼容性和性能
适合 SPA 路由切换、列表操作、卡片展开等场景。
CSS
返回首页