View Transitions API核心机制
CSS View Transitions API为Web应用提供了原生级别的页面过渡动画能力,无需依赖JavaScript动画库或Canvas渲染。该API在Chrome 111+和Firefox 128+中已稳定支持,核心思路是浏览器自动捕获新旧页面的视觉快照,在快照之间执行可自定义的过渡动画。
工作原理分四步:浏览器对当前页面状态生成旧快照(old snapshot);执行DOM更新操作;对新页面状态生成新快照(new snapshot);在两个快照之间运行动画。整个过程由浏览器合成器驱动,动画帧率稳定在60fps,不阻塞主线程。
同文档视图切换过渡
同文档内的视图切换是最简单的应用场景,例如SPA中的Tab切换或列表/详情视图切换:
document.startViewTransition(() => {
detailPanel.classList.remove("hidden");
listPanel.classList.add("hidden");
});
浏览器自动为发生变化的元素生成默认的淡入淡出动画。自定义过渡效果通过CSS伪元素控制:
::view-transition-old(root) {
animation: 300ms ease-out both fade-out;
}
::view-transition-new(root) {
animation: 300ms ease-in both fade-in;
}
root伪元素代表整个页面的过渡,适用于全局性视图切换。当需要更精细的控制时,给目标元素设置view-transition-name:
.user-avatar {
view-transition-name: avatar;
}
::view-transition-old(avatar) {
animation: 250ms ease-in-out both scale-down;
}
::view-transition-new(avatar) {
animation: 250ms ease-in-out both scale-up;
}
view-transition-name相同的元素在快照之间建立配对关系,浏览器自动计算它们的位置差异并生成插值动画。这一机制使共享元素过渡(Shared Element Transition)成为可能——头像从列表位置飞到详情页位置。
跨文档导航MPA过渡
View Transitions API同样支持多页面应用(MPA)的跨文档导航。Chrome 124+实现了跨文档视图过渡,无需JavaScript即可实现页面切换动画:
在CSS中声明导航过渡:
@view-transition {
navigation: auto;
}
此声明使浏览器在所有同源页面导航时自动触发视图过渡。配合view-transition-name实现跨页面的元素动画配对:
列表页中:
.card-image { view-transition-name: card-img-1; }
详情页中:
.hero-image { view-transition-name: card-img-1; }
当从列表页导航到详情页时,卡片图片会自动飞到详情页英雄图的位置,其余元素做默认淡入淡出。
控制特定导航类型的过渡行为:
@view-transition {
navigation: auto;
}
@media (prefers-reduced-motion: reduce) {
@view-transition { navigation: none; }
}
共享元素过渡动画实践
共享元素过渡(也叫Hero Animation)是View Transitions API最有价值的应用。实现一个从列表到详情的Hero过渡:
列表页HTML结构:
<div class="card" onclick="navigateToDetail(1)">
<img class="card-img" src="photo1.jpg" style="view-transition-name: item-1-img" />
<h3 style="view-transition-name: item-1-title">标题文本</h3>
</div>
JavaScript动态设置transition name:
function navigateToDetail(id) {
const img = document.querySelector(`.card-img[data-id="${id}"]`);
img.style.viewTransitionName = "detail-img";
const title = document.querySelector(`.card-title[data-id="${id}"]`);
title.style.viewTransitionName = "detail-title";
if (document.startViewTransition) {
document.startViewTransition(() => {
updateDOMForDetailView(id);
});
} else {
updateDOMForDetailView(id);
}
}
详情页的对应元素也设置相同的view-transition-name,浏览器自动计算位置差异并生成平滑飞入动画。
性能优化与降级方案
View Transitions动画由浏览器合成器执行,不触发主线程重排重绘,性能开销极低。但仍需注意:view-transition-name值在页面中必须唯一,重复的name会导致过渡失效;避免对大量元素同时设置独立的transition name,合成器为每个独立配对创建独立的合成层,过多层导致GPU显存压力。
降级策略:不支持View Transitions API的浏览器中startViewTransition为undefined,需做特性检测后降级为即时DOM更新:
const update = () => { /* DOM更新逻辑 */ };
document.startViewTransition ? document.startViewTransition(update) : update();
prefers-reduced-motion媒体查询需始终尊重,为运动敏感用户提供无动画的即时切换体验。在动画执行期间,浏览器在旧快照上层渲染新快照,交互事件被新快照接收,不会出现点击穿透问题。过渡期间的长任务会延迟快照捕获,建议在startViewTransition回调中避免繁重的DOM操作,保持回调执行在50ms以内。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/cssviewtransitionsapi-ye-mian-guo-du-dong-hua-yu-kua-wen/