View Transitions API:创建流畅的页面过渡
传统的网页通常以突兀的页面过渡为特点。当从一个页面导航到另一个页面时,当前页面消失,新页面突然出现。 这种生硬的体验多年来一直是Web平台的一个限制,尤其是与原生应用程序中常见的流畅过渡相比。
而View Transitions API的出现改变了这一切——这是一个强大的新浏览器功能,允许开发者在网页的不同状态之间或完全不同的页面之间创建平滑、动画化的过渡。 这一API代表了向Web带来更加精致、类似应用程序体验的重要一步。
什么是View Transitions API?
View Transitions API提供了一种标准化的方式来为Web内容的变化添加动画效果。它允许开发者在以下情况下创建无缝过渡:
- 在页面之间导航
- 在单个页面内更改DOM结构
- 更新UI组件或布局
从本质上讲,该API的工作原理是捕获页面当前状态的快照,捕获新状态的快照,然后在它们之间创建平滑的动画。 这一过程无需开发者手动跟踪和为单个元素添加动画。
浏览器支持
View Transitions API相对较新。截至2024年初,它支持以下浏览器:
- Chrome(自111版本起)
- Edge(基于Chromium)
- Opera(基于Chromium)
Firefox和Safari仍在开发其实现,但今天已经可以使用该API,只需为不支持的浏览器提供适当的回退方案。
基本用法
使用View Transitions API最简单的方法是通过document.startViewTransition()方法:
1if (document.startViewTransition) {2 document.startViewTransition(() => {3 // 在这里更新DOM4 document.body.innerHTML = newHTML;5 });6} else {7 // 对不支持该API的浏览器的回退方案8 document.body.innerHTML = newHTML;9}
传递给startViewTransition()的函数应包含更新DOM的代码。浏览器将:
- 捕获页面的当前状态
- 执行您的更新函数
- 捕获页面的新状态
- 在两种状态之间创建动画
处理宽高比变化
在使用View Transitions API时,一个常见的问题是当内容的宽高比在过渡期间发生变化时,过渡效果可能看起来不太自然。Jake Archibald在他的博客文章中详细讨论了这个问题及其解决方案。
非故意的宽高比变化
宽高比变化通常是非故意的。例如,当元素的字体大小或位置在过渡期间改变时:
.simple-text {font-size: 25px;}&.toggled {position: absolute;bottom: 32px;right: 32px;font-size: 9px;}
当我们切换这个类时,文本元素的宽高比会发生变化,这可能导致过渡动画看起来很奇怪。
btn.onclick = () => {document.querySelector('.simple-text').classList.toggle('toggled');}
下面是一个演示,展示了这种宽高比变化的效果:
宽高比变化演示
直接改变尺寸会导致宽高比变化,使过渡看起来不自然。
解决方案:使用transform代替直接改变尺寸
解决这个问题的一种方法是使用CSS transform来处理大小变化,而不是直接改变元素的尺寸:
.better-text {font-size: 25px;}&.toggled {position: absolute;bottom: 32px;right: 32px;transform: scale(0.36); /* 9px / 25px = 0.36 */transform-origin: bottom right;}
这种方法保持了元素的原始宽高比,同时通过缩放实现了大小变化,从而使过渡更加平滑。
使用view-transition-name处理特定元素
对于需要特别关注的元素,我们可以使用view-transition-name属性来单独处理它们的过渡:
.image-container {view-transition-name: my-image;}/* 自定义这个特定元素的过渡 */::view-transition-group(my-image) {animation-duration: 0.6s;}::view-transition-old(my-image),::view-transition-new(my-image) {/* 防止内容被裁剪 */overflow: clip;}
处理图像宽高比变化
对于图像,宽高比变化是一个特别常见的问题。例如,从缩略图到全尺寸图像的过渡:
.thumbnail {width: 100px;height: 100px;object-fit: cover;view-transition-name: selected-image;}.full-image {width: 100%;height: auto;view-transition-name: selected-image;}/* 自定义图像过渡 */::view-transition-group(selected-image) {animation-duration: 0.5s;}::view-transition-old(selected-image),::view-transition-new(selected-image) {/* 使用 'contain' 而不是默认的 'cover' */object-fit: contain;}
高级技巧:使用伪元素保持宽高比
对于更复杂的情况,我们可以使用伪元素和CSS变量来保持宽高比:
.advanced-container {position: relative;view-transition-name: my-element;}.advanced-container::before {content: '';display: block;padding-top: var(--aspect-ratio, 56.25%); /* 默认16:9比例 */}.advanced-container .content {position: absolute;top: 0;left: 0;width: 100%;height: 100%;}/* 在JavaScript中设置CSS变量 */// element.style.setProperty('--aspect-ratio', '75%'); // 4:3比例
单页应用程序过渡
对于SPA,您可以将View Transitions API与路由器集成,以在视图之间创建平滑过渡:
// 使用假设的路由器的示例router.beforeNavigate((to, from, next) => {if (document.startViewTransition) {document.startViewTransition(() => {next();});} else {next();}});
多页应用程序过渡
对于传统的多页应用程序,您可以将API与Navigation API一起使用:
1document.addEventListener('click', (e) => {2 // 只处理链接点击3 if (e.target.tagName !== 'A') return;45 // 只处理同源导航6 const href = e.target.href;7 if (!href || !href.startsWith(window.location.origin)) return;89 // 阻止默认导航10 e.preventDefault();1112 // 如果可用,使用View Transitions API13 if (document.startViewTransition) {14 document.startViewTransition(async () => {15 // 获取新页面16 const response = await fetch(href);17 const text = await response.text();1819 // 提取我们想要显示的内容20 const parser = new DOMParser();21 const newDocument = parser.parseFromString(text, 'text/html');22 const newContent = newDocument.querySelector('main').innerHTML;2324 // 更新当前页面25 document.querySelector('main').innerHTML = newContent;2627 // 更新URL28 window.history.pushState({}, '', href);29 });30 } else {31 // 回退到正常导航32 window.location.href = href;33 }34});
与Next.js集成
Next.js 15.2引入了对React中View Transitions API的实验性支持。要启用此功能,请在您的next.config.js文件中添加以下内容 [^1]:
module.exports = {experimental: {viewTransition: true,},};
此功能高度实验性,可能在未来的版本中发生变化 [^2]。它建立在View Transitions的原生浏览器实现之上,允许您在Next.js应用程序的不同视图和组件之间创建平滑过渡。
无障碍性考虑
在实现视图过渡时,请记住无障碍性:
- 使用prefers-reduced-motion媒体查询尊重用户对减少动画的偏好
- 确保在过渡期间内容保持可访问
- 为动态内容更改提供适当的ARIA属性
// 检查减少动画偏好const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;if (!prefersReducedMotion && document.startViewTransition) {document.startViewTransition(() => {// 更新DOM});} else {// 不带动画的直接更新}
结论
View Transitions API代表了Web动画能力的重大进步。它提供了一种标准化、高性能的方式来创建平滑过渡,这在以前没有复杂的JavaScript库是很难或不可能实现的。
处理宽高比变化是使用View Transitions API时的一个关键考虑因素。通过使用本文中讨论的技术,如CSS transform、适当的object-fit属性和伪元素,您可以创建更加自然和专业的过渡效果。
随着浏览器支持的不断增长,我们可以期待看到更多的网站采用这一API来创建更具吸引力、类似应用程序的体验。与React和Next.js等框架的集成将使开发者更容易访问它。
虽然仍在发展中,但View Transitions API已经可以在今天进行实验性使用,只需提供适当的回退方案。这是一个开始探索这一新功能并思考它如何增强您的Web项目的激动人心的时刻。