View Transitions API 入门教程
一句话理解:DOM 发生变化时,浏览器自动帮你做"截图过渡",让变化看起来平滑自然。
一、为什么需要 View Transitions?
场景:页面内容切换太生硬
想象一个常见的场景:点击按钮切换页面内容,旧内容瞬间消失,新内容突然出现,用户感觉很突兀。
css
❌ 不使用 View Transitions:
┌─────────────┐ ┌─────────────┐
│ 方块A │ → │ 方块A‑变色 │ (直接闪现,没有任何过渡)
│ [蓝色] │ │ [红色] │
└─────────────┘ └─────────────┘
✅ 使用 View Transitions:
┌─────────────
│ 方块A │
│ [蓝色] │ ──► 慢慢淡出
└─────────────┘
│
▼
┌─────────────┐
│ 方块A‑变色 │ ◄── 慢慢淡入
│ [红色] │
└─────────────┘
传统的 CSS transition 解决不了这个问题:
css
/* 这只能对单个元素的属性变化做动画 */
.box {
transition: background-color 0.5s;
}
当整个 DOM 结构(元素被替换或内容完全改变)发生变化时,CSS transition 无能为力。
View Transitions API 的解决:
浏览器在 DOM 变化前后各"截一张图",然后在两张截图之间做平滑过渡动画。
二、View Transitions vs CSS Transition
| 维度 | CSS Transition / Animation | View Transitions API |
|---|---|---|
| 适用对象 | 单个元素的属性变化(如颜色、大小) | 整个 DOM 的变化(元素替换、内容切换) |
| 触发方式 | CSS 属性变化自动触发 | JavaScript 调用 startViewTransition() |
| 动画内容 | 属性值的插值动画 | 新旧 DOM 截图之间的过渡动画 |
| 复杂度 | 简单,纯 CSS 即可 | 需要 JS 配合,但功能更强大 |
| 浏览器支持 | 全部支持 | Chrome 115+、Edge 115+、Firefox 115+ |
三、完整示例
3.1 效果对比
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>View Transitions 使用 vs 不使用对比</title>
<style>
body {
font-family: system-ui;
padding: 24px;
max-width: 700px;
}
.wrap {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 30px;
}
.panel {
border: 1px solid #ccc;
padding: 16px;
border-radius: 8px;
}
.box {
width: 180px;
height: 180px;
border-radius: 12px;
display: grid;
place-items: center;
color: #fff;
font-size: 20px;
cursor: pointer;
margin: 10px 0;
}
.blue { background: #2563eb; }
.red { background: #dc2626; }
/* ===== 自定义过渡动画时长 ===== */
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.7s;
}
button {
padding: 8px 14px;
cursor: pointer;
}
</style>
</head>
<body>
<h2>View Transitions 对比演示</h2>
<div class="wrap">
<!-- 不使用 ViewTransition:直接修改DOM,直接闪现 -->
<div class="panel">
<h4>❌ 不使用 ViewTransitions</h4>
<div id="box1" class="box blue">方块A</div>
<button id="btn1">切换颜色</button>
<p>效果:直接瞬间闪变,没有动画</p>
</div>
<!-- 使用 ViewTransition:带平滑过渡动画 -->
<div class="panel">
<h4>✅ 使用 ViewTransitions</h4>
<div id="box2" class="box blue">方块B</div>
<button id="btn2">切换颜色</button>
<p>效果:淡入淡出平滑过渡</p>
</div>
</div>
<script>
const box1 = document.querySelector('#box1');
const box2 = document.querySelector('#box2');
const btn1 = document.querySelector('#btn1');
const btn2 = document.querySelector('#btn2');
let state1 = true;
let state2 = true;
// --------------------------
// 不使用 View Transitions
// 直接修改 DOM,无任何过渡
// --------------------------
btn1.onclick = function () {
state1 = !state1;
if (state1) {
box1.className = 'box blue';
box1.textContent = '方块A';
} else {
box1.className = 'box red';
box1.textContent = '方块A-变色';
}
};
// --------------------------
// 使用 View Transitions API
// --------------------------
btn2.onclick = function () {
if (!document.startViewTransition) {
// 浏览器不支持则降级直接修改DOM
toggleBox2();
return;
}
document.startViewTransition(toggleBox2);
};
function toggleBox2() {
state2 = !state2;
if (state2) {
box2.className = 'box blue';
box2.textContent = '方块B';
} else {
box2.className = 'box red';
box2.textContent = '方块B-变色';
}
}
</script>
</body>
</html>
3.2 效果对比
| 操作 | 不使用 View Transitions | 使用 View Transitions |
|---|---|---|
| 点击按钮 | 颜色和内容瞬间切换 | 旧内容淡出,新内容淡入 |
| 视觉感受 | 生硬、突兀 | 平滑、自然 |
四、核心 API 详解
4.1 基本用法
js
// 最简形式:把 DOM 修改逻辑包在 startViewTransition 中
document.startViewTransition(() => {
// 在这里修改 DOM
updateDOM();
});
4.2 执行流程
sql
用户点击按钮
│
▼
┌─────────────────────────────────────────┐
│ document.startViewTransition(callback) │
└─────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ ① 捕获旧快照 │ ← 浏览器截取当前 DOM 的"照片"
│ (old) │
└─────────────────┘
│
▼
┌─────────────────┐
│ ② 执行回调 │ ← 执行你的 DOM 修改代码
│ (callback) │
└─────────────────┘
│
▼
┌─────────────────┐
│ ③ 捕获新快照 │ ← 浏览器截取修改后的 DOM "照片"
│ (new) │
└─────────────────┘
│
▼
┌─────────────────┐
│ ④ 播放过渡动画 │ ← old 淡出 + new 淡入
│ (0.7s) │
└─────────────────┘
4.3 自定义过渡动画
修改动画时长:
css
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.7s;
}
修改动画类型(默认是淡入淡出):
css
/* 让旧视图向左滑出 */
::view-transition-old(root) {
animation: slide-out 0.7s ease-in-out;
}
/* 让新视图从右侧滑入 */
::view-transition-new(root) {
animation: slide-in 0.7s ease-in-out;
}
@keyframes slide-out {
to { transform: translateX(-100%); opacity: 0; }
}
@keyframes slide-in {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
五、降级策略
5.1 特性检测
js
if (document.startViewTransition) {
// 支持 View Transitions
document.startViewTransition(updateDOM);
} else {
// 不支持,直接修改 DOM
updateDOM();
}
5.2 封装为工具函数
js
function withTransition(callback) {
if (document.startViewTransition) {
return document.startViewTransition(callback);
}
// 不支持时直接执行
callback();
return null;
}
// 使用方式
btn.onclick = () => {
withTransition(() => {
// 修改 DOM 的逻辑
toggleContent();
});
};
六、浏览器兼容性
| 浏览器 | 最低版本 | 备注 |
|---|---|---|
| Chrome | 115+ | ✅ 完全支持 |
| Edge | 115+ | ✅ 完全支持 |
| Firefox | 115+ | ✅ 支持 |
| Safari | 不支持 | ❌ 需要 Polyfill 或降级 |
七、常见应用场景
7.1 单页应用(SPA)页面切换
js
// 路由切换时添加过渡
router.beforeEach((to, from, next) => {
if (document.startViewTransition) {
document.startViewTransition(() => {
next();
});
} else {
next();
}
});
7.2 图片画廊切换
js
function showImage(index) {
withTransition(() => {
gallery.innerHTML = `<img src="${images[index]}">`;
});
}
7.3 列表项展开/收起
js
function toggleItem(id) {
withTransition(() => {
const item = document.querySelector(`[data-id="${id}"]`);
item.classList.toggle('expanded');
});
}
八、与 CSS Transition 的对比总结
| 场景 | 推荐方案 | 原因 |
|---|---|---|
| 单个元素的 hover 效果 | CSS Transition | 简单,无需 JS |
| 颜色/大小等属性变化 | CSS Transition | 浏览器自动插值 |
| 整个 DOM 内容切换 | View Transitions | 浏览器自动截图过渡 |
| 页面路由切换 | View Transitions | 提供类似原生 App 的过渡体验 |
| 需要复杂控制 | CSS Animation + JS | 完全自定义动画 |
九、总结
- View Transitions API = 浏览器自动帮你做"新旧截图过渡"
- 核心方法 :
document.startViewTransition(callback) - 自定义动画 :通过
::view-transition-old()和::view-transition-new()伪元素 - 必须做降级 :Safari 不支持,需要
if (document.startViewTransition)判断 - 最佳实践:用工具函数封装,统一处理降级逻辑