View Transition API 实战:SPA、跨文档导航与渐进增强
本文目录
View Transition API 把“旧视图快照、DOM 更新、新视图快照、播放动画”交给浏览器协调。它适用于 SPA 内的状态切换,也能为同源 MPA 文档导航提供 CSS 转场。它不会替你完成路由、数据加载、焦点管理、滚动恢复或权限检查;动画只是体验层,导航和内容仍必须在不支持该 API 时正常工作。
先分清两种转场
同文档转场由 JavaScript 启动:把快速、确定的 DOM 更新回调交给 document.startViewTransition(update)。浏览器先保存旧状态,再运行回调并捕获新状态。用户等待网络的时间不应放进转场回调;先取得路由数据并准备好 DOM 更新,再开始短动画,否则快照阶段会被异步请求拖长。
function commitViewChange(updateDOM) {
const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (reduceMotion || typeof document.startViewTransition !== 'function') {
updateDOM();
return;
}
document.startViewTransition(updateDOM);
}
// 路由数据先请求完成,再在短回调中提交视图变化。
commitViewChange(() => renderRoute(preparedRoute));
不支持 API 或用户要求减少动态效果时,代码直接更新 DOM,不依赖动画才能进入页面。框架路由器已有转场钩子时,优先接入其导航提交边界,避免同一次路由被多个组件重复启动转场。
跨文档转场不需要 SPA 路由器,也不需要 JavaScript。来源页和目标页都要在样式中声明加入;导航必须满足当前实现要求的同源条件:
@view-transition {
navigation: auto;
}
@media (prefers-reduced-motion: no-preference) {
::view-transition-old(root) {
animation: page-out 120ms ease-out both;
}
::view-transition-new(root) {
animation: page-in 180ms ease-out both;
}
}
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none;
}
}
@keyframes page-out {
to { opacity: 0; }
}
@keyframes page-in {
from { opacity: 0; }
}
把规则放进两页都会加载的共享 CSS,并核实首屏关键内容在导航动画前已稳定渲染。跨域登录、第三方支付等跳转不应期待共享快照;不满足条件时让浏览器执行普通导航即可。高级的 pageswap、pagereveal 生命周期能力有更窄的浏览器支持面,不要把它们误当成基本渐进增强的前提。
共享元素与快照命名
默认根视图会交叉淡入淡出。若列表中的书封面要与详情页的封面配对,可以给两边对应元素使用相同的 view-transition-name:
.book-cover {
view-transition-name: book-cover;
}
::view-transition-old(book-cover),
::view-transition-new(book-cover) {
animation-duration: 180ms;
}
在同一个被捕获视图里,每个自定义名字必须唯一;同一时刻有两个可见元素共用 book-cover,转场可能被跳过。列表很多项时不要按位置硬编码几十个名字;match-element 可让浏览器为元素分配内部名称,但它依赖同一文档中的元素身份,不能拿它跨文档配对。只给真正需要连续感的少数元素命名,其余内容保留默认根动画。
常见故障与体验边界
- 动画跳过:检查旧页与新页是否都 opt in、是否同源、目标选择器是否存在,以及快照中是否出现重复名称。用浏览器开发者工具观察转场伪元素,不要只靠肉眼猜测。
- 首屏闪动:两页的关键 CSS、字体和共享元素尺寸应尽量稳定。异步注入主题、导航高度或封面比例会让新旧快照错位;优先固定布局尺寸,必要时明确阻塞关键内容渲染。
- 内容短暂不可点:动画期间旧视图是快照,新视图才是可交互内容。避免用过长转场遮挡焦点;路由变化后仍应把焦点移到新页面标题或主内容,更新标题、历史记录、读屏播报和滚动位置。
- 页面发闷或掉帧:整页快照可能覆盖大图、视频或复杂画布。优先转场局部元素,压短时长,并在低端手机、后台标签恢复、长列表和系统减弱动态效果设置下实测。
- 框架重复动画:页面切换、组件入场和 CSS transition 同时运行时,效果会叠加。定义唯一的导航所有者,组件级动画只处理局部状态变化。
MDN 将基础 View Transition API 与 view-transition-name 标为 Baseline 2025;这不是“所有旧浏览器和嵌入式 WebView 都支持”的保证。发布前仍按真实访客浏览器矩阵验证 SPA/MPA、前进后退、硬刷新、无 JavaScript、键盘导航和减少动态效果;unsupported 路径必须保留可用的普通页面更新。
参考:MDN View Transition API、MDN 使用 View Transition API、MDN view-transition-name、MDN element-scoped transitions、CSS View Transitions Module。
Live Notes
留言提交后会先进入审核,审核通过后对其他读者公开。