CSS View Transitions API:页面切换从未如此优雅
CSS 是流动的韵律,JS 是叙事的节奏。
一、第一次看到 View Transitions
去年在一个技术分享会上,我看到有人演示了 View Transitions API——页面切换之间,元素平滑地从一个位置"飞"到另一个位置,那种流畅和自然的感觉让我当场就坐直了身体。
在此之前,实现类似效果需要借助 Framer Motion 或 GSAP 等 JavaScript 动画库,而且代码量不小。View Transitions API 把这一切简化到了极致——一个<meta>标签或者几行 JavaScript 就能实现电影级的页面过渡效果。
二、基础用法:SPA 中的视图过渡
在单页应用(SPA)中,View Transitions API 使用起来特别简单:
// 基础用法:在页面切换时触发过渡 async function navigateTo(url) { event.preventDefault(); // 开始视图过渡 const transition = document.startViewTransition(() => { // 更新 DOM updatePageContent(url); }); // 等待过渡完成 await transition.finished; } // 最简单的 SPA 路由集成 document.querySelectorAll('a').forEach(link => { link.addEventListener('click', async (e) => { e.preventDefault(); const href = link.getAttribute('href'); if (document.startViewTransition) { await document.startViewTransition(() => { window.location.href = href; }).ready; } else { window.location.href = href; } }); });/* 默认的交叉淡入淡出效果 */ ::view-transition-old(root) { animation: 0.4s ease-out both fade-out; } ::view-transition-new(root) { animation: 0.4s ease-out both fade-in; } @keyframes fade-out { from { opacity: 1; } to { opacity: 0; } } @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }三、自定义过渡效果:让元素"飞"起来
View Transitions API 最强大的功能是让特定元素在不同的页面状态之间平滑过渡:
/* 为文章卡片和文章详情页的图片创建关联过渡 */ .article-card-thumbnail { view-transition-name: article-thumbnail; } .article-detail-image { view-transition-name: article-thumbnail; } /* 自定义过渡动画 */ ::view-transition-old(article-thumbnail) { animation: 0.3s ease-out both shrink-out; } ::view-transition-new(article-thumbnail) { animation: 0.3s ease-out both grow-in; } @keyframes shrink-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.5); } } @keyframes grow-in { from { opacity: 0; transform: scale(1.5); } to { opacity: 1; transform: scale(1); } }<!-- 文章列表页 --> <div class="article-card"> <img class="article-card-thumbnail" src="thumb.jpg" alt="文章缩略图" > <h2>文章标题</h2> </div> <!-- 文章详情页 --> <article> <img class="article-detail-image" src="thumb.jpg" alt="文章缩略图" > <h1>文章标题</h1> <p>文章内容...</p> </article>四、多元素过渡:编排复杂的动画
可以同时为多个元素创建独立的过渡效果:
/* 为不同的元素分配过渡名称 */ .header-logo { view-transition-name: header-logo; } .nav-menu { view-transition-name: nav-menu; } .page-title { view-transition-name: page-title; } .sidebar { view-transition-name: sidebar; } /* 每个元素可以定义自己的过渡动画 */ ::view-transition-old(header-logo) { animation: 0.3s ease-out both slide-down; } ::view-transition-new(header-logo) { animation: 0.3s ease-out both slide-up; } ::view-transition-old(nav-menu) { animation: 0.2s ease-out both fade-out; } ::view-transition-new(nav-menu) { animation: 0.3s 0.1s ease-out both fade-in; } ::view-transition-old(page-title) { animation: 0.2s ease-out both fade-out; } ::view-transition-new(page-title) { animation: 0.3s 0.15s ease-out both slide-from-right; } @keyframes slide-down { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } @keyframes slide-up { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } @keyframes slide-from-right { from { opacity: 0; transform: translateX(30px); } to { opacity: 1; transform: translateX(0); } }五、MPA(多页应用)中的跨页面过渡
View Transitions API 也支持传统的多页应用(MPA)。在 MPA 中,只需要在 HTML 中添加一个<meta>标签:
<!-- 在页面间启用视图过渡 --> <meta name="view-transition" content="same-origin">/* 跨页面过渡动画 */ @keyframes page-fade-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } @keyframes page-fade-out { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-10px); } } ::view-transition-old(root) { animation: 0.3s ease-in both page-fade-out; } ::view-transition-new(root) { animation: 0.3s ease-out both page-fade-in; }六、结合 prefers-reduced-motion
记得要考虑用户对动画的偏好设置:
/* 尊重用户的动画偏好 */ @media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; animation-duration: 0.01ms !important; } } /* 或者提供更克制的过渡 */ @media (prefers-reduced-motion: reduce) { ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.15s; } }七、实用技巧与注意事项
在实际项目中使用 View Transitions API 时,有一些值得注意的技巧:
// 检查浏览器支持 if (!document.startViewTransition) { // 降级处理:直接更新 DOM updateContent(); } else { await document.startViewTransition(updateContent).finished; } // 等待关键资源加载后再过渡 async function transitionWithLoading(url) { // 先显示加载状态 showLoadingIndicator(); // 预加载下一页的内容 const response = await fetch(url); const html = await response.text(); // 开始视图过渡 const transition = document.startViewTransition(() => { updateDOM(html); }); // 等待过渡准备好 await transition.ready; // 隐藏加载状态 hideLoadingIndicator(); } // 自定义过渡的持续时间 async function customDurationTransition() { const transition = document.startViewTransition(() => updateContent()); // 等待伪元素创建完成 await transition.ready; // 动态调整动画时长 document.documentElement.animate( { opacity: [0, 1] }, { duration: 500, pseudoElement: '::view-transition-new(root)' } ); }graph TD A[CSS样式层] --> B[变量定义] A --> C[布局系统] A --> D[动画效果] B --> E[主题色彩] B --> F[间距系统] C --> G[Flexbox] C --> H[Grid]八、结语:动画的未来
View Transitions API 代表了 Web 平台对动画体验的一次重要升级。它把页面切换这个最常见的用户交互场景,从一个需要 JavaScript 库才能做好的"高级功能",变成了浏览器原生支持的"基础能力"。
这让我想起当年 CSS3 动画刚普及时的情景——起初大家都用 jQuery 做动画,后来 CSS transition 和 animation 成为标准后,一切变得简单了。View Transitions API 正在重复这个路径。