CSS视图过渡View Transitions API:页面切换动画
教程概述
视图过渡(View Transitions)API 是一项现代Web技术,用于创建流畅的页面状态切换动画效果。该技术通过捕获DOM状态的快照,并在状态变化时在这些快照之间创建平滑过渡,使开发者能够以声明式方式实现复杂的动画效果,而无需编写大量JavaScript或CSS代码。
本教程将全面介绍View Transitions API的核心概念、使用方法和实际应用场景,帮助您在找找网项目中实现更优雅的用户界面过渡效果。
核心概念与基本原理
视图过渡API的工作原理基于状态快照的概念。当触发视图过渡时,浏览器会执行以下步骤:
- 捕获当前DOM状态作为旧视图快照
- 暂停页面渲染,防止中间状态闪烁
- 执行DOM更新到新状态
- 捕获新DOM状态作为新视图快照
- 创建伪元素树来托管新旧快照
- 执行过渡动画,在两个状态间平滑转换
- 清理伪元素,恢复页面正常交互
这一过程创建了一个伪元素树结构:
::view-transition
└─ ::view-transition-group(root)
└─ ::view-transition-image-pair(root)
├─ ::view-transition-old(root)
└─ ::view-transition-new(root)基本用法与示例
单页面应用中的视图过渡
以下是一个在单页面应用中使用View Transitions API的完整示例:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>视图过渡示例 - 找找网</title>
<style>
.zzw_page {
padding: 20px;
transition: all 0.3s;
}
.zzw_button {
padding: 10px 20px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin: 10px;
}
.zzw_content {
padding: 20px;
border: 1px solid #ddd;
margin: 20px 0;
border-radius: 4px;
}
/* 自定义过渡动画 */
::view-transition-old(root) {
animation: zzw_fade-out 0.5s ease-in;
}
::view-transition-new(root) {
animation: zzw_fade-in 0.5s ease-out;
}
@keyframes zzw_fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes zzw_fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
</style>
</head>
<body>
<div class="zzw_page">
<h1>找找网视图过渡示例</h1>
<button class="zzw_button" id="zzw_toggleButton">切换内容</button>
<div class="zzw_content" id="zzw_contentArea">
<h2>初始内容</h2>
<p>这是视图过渡API演示的初始内容。</p>
</div>
</div>
<script>
const zzw_toggleButton = document.getElementById('zzw_toggleButton');
const zzw_contentArea = document.getElementById('zzw_contentArea');
let zzw_currentView = 'initial';
zzw_toggleButton.addEventListener('click', () => {
// 检查浏览器支持情况
if (!document.startViewTransition) {
zzw_switchContent();
return;
}
// 使用视图过渡API
document.startViewTransition(() => {
zzw_switchContent();
});
});
function zzw_switchContent() {
if (zzw_currentView === 'initial') {
zzw_contentArea.innerHTML = `
<h2>新内容已加载</h2>
<p>这是通过视图过渡API显示的新内容。</p>
<p>注意内容切换时的平滑过渡效果。</p>
`;
zzw_currentView = 'new';
} else {
zzw_contentArea.innerHTML = `
<h2>初始内容</h2>
<p>这是视图过渡API演示的初始内容。</p>
`;
zzw_currentView = 'initial';
}
}
</script>
</body>
</html>多页面应用中的视图过渡
对于多页面应用,现在可以通过一行CSS代码启用基础的视图过渡效果:
@view-transition {
navigation: auto;
}将上述代码添加到站点的每个页面样式表中,即可在页面导航时启用默认的交叉淡入淡出效果。
高级功能与自定义动画
元素级过渡与视图过渡命名
View Transitions API 允许为特定元素创建独立的过渡效果,通过view-transition-name属性实现:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>元素级视图过渡 - 找找网</title>
<style>
.zzw_card {
width: 300px;
padding: 20px;
margin: 20px;
border: 1px solid #ccc;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.zzw_featured {
view-transition-name: zzw-featured-card;
}
.zzw_image {
width: 100%;
height: 200px;
background-color: #f0f0f0;
margin-bottom: 10px;
view-transition-name: zzw-main-image;
}
/* 自定义元素过渡动画 */
::view-transition-old(zzw-featured-card),
::view-transition-new(zzw-featured-card) {
animation-duration: 0.8s;
}
::view-transition-old(zzw-main-image) {
animation: zzw_scale-out 0.6s ease-in;
}
::view-transition-new(zzw-main-image) {
animation: zzw_scale-in 0.6s ease-out;
}
@keyframes zzw_scale-out {
from {
transform: scale(1);
opacity: 1;
}
to {
transform: scale(0.5);
opacity: 0;
}
}
@keyframes zzw_scale-in {
from {
transform: scale(0.5);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
</style>
</head>
<body>
<div class="zzw_card zzw_featured">
<div class="zzw_image"></div>
<h3>特色内容卡片</h3>
<p>此卡片具有自定义的视图过渡效果。</p>
</div>
<button class="zzw_button" id="zzw_updateCard">更新卡片</button>
<script>
const zzw_updateButton = document.getElementById('zzw_updateCard');
const zzw_card = document.querySelector('.zzw_card');
zzw_updateButton.addEventListener('click', () => {
if (!document.startViewTransition) {
zzw_toggleCardContent();
return;
}
document.startViewTransition(() => {
zzw_toggleCardContent();
});
});
function zzw_toggleCardContent() {
const zzw_image = document.querySelector('.zzw_image');
const zzw_title = zzw_card.querySelector('h3');
const zzw_content = zzw_card.querySelector('p');
if (zzw_title.textContent === '特色内容卡片') {
zzw_image.style.backgroundColor = '#e0f0ff';
zzw_title.textContent = '已更新的卡片';
zzw_content.textContent = '卡片内容已通过视图过渡API更新,注意图片和内容的过渡效果。';
} else {
zzw_image.style.backgroundColor = '#f0f0f0';
zzw_title.textContent = '特色内容卡片';
zzw_content.textContent = '此卡片具有自定义的视图过渡效果。';
}
}
</script>
</body>
</html>控制过渡生命周期
View Transitions API 提供了对过渡生命周期的精细控制:
// 视图过渡生命周期示例
function zzw_executeViewTransition(updateCallback) {
// 检查浏览器支持
if (!document.startViewTransition) {
updateCallback();
return;
}
// 启动视图过渡
const zzw_transition = document.startViewTransition(async () => {
await updateCallback();
});
// 更新回调完成时
zzw_transition.updateCallbackDone.then(() => {
console.log('DOM更新已完成');
});
// 过渡准备就绪时
zzw_transition.ready.then(() => {
console.log('过渡动画即将开始');
});
// 过渡完成时
zzw_transition.finished.then(() => {
console.log('过渡动画已完成');
});
}
// 使用示例
document.getElementById('zzw_myButton').addEventListener('click', () => {
zzw_executeViewTransition(() => {
// 执行DOM更新
document.getElementById('zzw_content').textContent = '内容已更新';
});
});浏览器兼容性与最佳实践
浏览器兼容性现状
View Transitions API 的浏览器支持情况如下:
| 浏览器 | 支持版本 | 支持状态 |
|---|---|---|
| Chrome | 111+ | 完全支持 |
| Edge | 111+ | 完全支持 |
| Safari | 18.2+ | 完全支持 |
| Firefox | 未支持 | 开发中 |
渐进增强实现
考虑到浏览器兼容性,实现时应采用渐进增强策略:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>渐进增强视图过渡 - 找找网</title>
<style>
.zzw_content {
padding: 20px;
transition: opacity 0.3s;
}
/* 仅在有视图过渡支持的浏览器中应用自定义动画 */
@supports (view-transition-name: none) {
::view-transition-old(root),
::view-transition-new(root) {
animation-duration: 0.5s;
}
.zzw_animated-element {
view-transition-name: zzw-animated-element;
}
}
/* 减少动画偏好设置 */
@media (prefers-reduced-motion: reduce) {
::view-transition-old(root),
::view-transition-new(root) {
animation: none;
}
}
</style>
</head>
<body>
<div class="zzw_content" id="zzw_mainContent">
<h1>渐进增强示例</h1>
<p>此示例在不支持View Transitions API的浏览器中仍能正常工作。</p>
</div>
<button class="zzw_button" id="zzw_updateContent">更新内容</button>
<script>
const zzw_updateButton = document.getElementById('zzw_updateContent');
zzw_updateButton.addEventListener('click', () => {
// 特性检测
if (!document.startViewTransition) {
// 不支持API时的降级方案
zzw_updateContent();
return;
}
// 支持API时的增强体验
document.startViewTransition(() => {
zzw_updateContent();
});
});
function zzw_updateContent() {
const zzw_content = document.getElementById('zzw_mainContent');
const zzw_currentText = zzw_content.querySelector('p').textContent;
if (zzw_currentText.includes('渐进增强')) {
zzw_content.querySelector('h1').textContent = '内容已更新';
zzw_content.querySelector('p').textContent =
'视图过渡API提供了平滑的过渡效果,在不支持的浏览器中会降级为直接更新。';
} else {
zzw_content.querySelector('h1').textContent = '渐进增强示例';
zzw_content.querySelector('p').textContent =
'此示例在不支持View Transitions API的浏览器中仍能正常工作。';
}
}
// 检测减少动画偏好
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
// 在用户偏好减少动画时跳过过渡
document.startViewTransition = undefined;
}
</script>
</body>
</html>性能优化建议
- 精简DOM更新:将昂贵的DOM操作集中在startViewTransition回调中,减少布局颠簸
- 避免长时间运行的任务:确保updateCallback不会阻塞主线程过长时间
- 谨慎使用复杂滤镜:在伪元素上使用大滤镜或阴影可能影响性能
- 尊重用户偏好:始终检测
prefers-reduced-motion设置并提供适当的回退
实际应用场景
图片库过渡效果
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>图片库视图过渡 - 找找网</title>
<style>
.zzw_gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
padding: 20px;
}
.zzw_gallery img {
width: 100%;
height: 200px;
object-fit: cover;
cursor: pointer;
view-transition-name: var(--zzw-transition-name);
}
.zzw_lightbox {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 1000;
}
.zzw_lightbox img {
max-width: 90%;
max-height: 90%;
view-transition-name: zzw-lightbox-image;
}
/* 自定义图片过渡效果 */
::view-transition-old(zzw-lightbox-image),
::view-transition-new(zzw-lightbox-image) {
animation-duration: 0.5s;
}
</style>
</head>
<body>
<div class="zzw_gallery" id="zzw_gallery">
<img src="https://picsum.photos/seed/1/300/200" alt="示例图片1"
style="--zzw-transition-name: zzw-gallery-1;">
<img src="https://picsum.photos/seed/2/300/200" alt="示例图片2"
style="--zzw-transition-name: zzw-gallery-2;">
<img src="https://picsum.photos/seed/3/300/200" alt="示例图片3"
style="--zzw-transition-name: zzw-gallery-3;">
</div>
<div class="zzw_lightbox" id="zzw_lightbox">
<img src="" alt="放大视图" id="zzw_lightboxImage">
</div>
<script>
const zzw_gallery = document.getElementById('zzw_gallery');
const zzw_lightbox = document.getElementById('zzw_lightbox');
const zzw_lightboxImage = document.getElementById('zzw_lightboxImage');
zzw_gallery.addEventListener('click', (event) => {
if (event.target.tagName === 'IMG') {
zzw_openLightbox(event.target);
}
});
zzw_lightbox.addEventListener('click', () => {
zzw_closeLightbox();
});
function zzw_openLightbox(clickedImage) {
if (!document.startViewTransition) {
zzw_lightboxImage.src = clickedImage.src;
zzw_lightbox.style.display = 'flex';
return;
}
// 设置lightbox图片的过渡名称与点击的图片相同
zzw_lightboxImage.style.viewTransitionName =
clickedImage.style.getPropertyValue('--zzw-transition-name');
document.startViewTransition(() => {
zzw_lightboxImage.src = clickedImage.src;
zzw_lightbox.style.display = 'flex';
});
}
function zzw_closeLightbox() {
if (!document.startViewTransition) {
zzw_lightbox.style.display = 'none';
return;
}
document.startViewTransition(() => {
zzw_lightbox.style.display = 'none';
// 重置过渡名称
zzw_lightboxImage.style.viewTransitionName = 'zzw-lightbox-image';
});
}
</script>
</body>
</html>常见问题与解决方案
视图过渡被取消的情况
视图过渡可能因以下原因被取消:
view-transition-name值重复- DOM状态变化过于复杂
- 页面包含
beforeunload事件监听器 - 过渡过程中发生错误
调试视图过渡
可以使用Chrome开发者工具进行调试:
- 打开More Tools → Animations面板
- 捕获动画并调整播放速度
- 检查视图过渡伪元素
教程知识点总结
| 知识点 | 知识内容 |
|---|---|
| View Transitions API 定义 | 一项现代Web技术,用于创建DOM状态之间的平滑过渡动画 |
| 核心原理 | 通过捕获新旧DOM状态快照,并在伪元素树上执行过渡动画 |
| 基本用法 | 使用document.startViewTransition(updateCallback)启动过渡 |
| 多页面应用支持 | 通过@view-transition { navigation: auto; }启用页面间过渡 |
| 元素级过渡 | 使用view-transition-name属性为特定元素创建独立过渡效果 |
| 生命周期控制 | 通过updateCallbackDone、ready和finishedPromise监控过渡状态 |
| 浏览器兼容性 | 目前Chrome、Edge和Safari新版支持,Firefox尚未支持 |
| 渐进增强策略 | 通过特性检测提供不支持浏览器下的降级方案 |
| 性能优化 | 精简DOM操作、避免长时间任务、尊重用户动画偏好 |
| 无障碍考虑 | 检测prefers-reduced-motion媒体查询并为偏好减少动画的用户跳过过渡 |
View Transitions API 提供了创建现代化、流畅的用户界面过渡的强大能力。通过本教程介绍的概念和技术,找找网开发者可以在项目中有效应用这一技术,提升用户体验,同时确保在不支持的环境中保持功能正常。

