transition不能用于页面切换,因其仅支持单元素可插值属性的同步状态变化,而跨页切换是DOM整体替换,无过渡帧可插值;必须用document.startViewTransition()包裹同步DOM更新。

直接用 document.startViewTransition(),别碰 transition 或 @keyframes 做跨页动效——它们根本不是为这个设计的。
为什么 transition 不能用于页面切换
transition 只响应单个元素上可插值属性(如 opacity、transform)的状态变化,且要求前后状态在同一 DOM 树中。跨页面切换本质是 DOM 整体替换(比如 document.body.innerHTML = newHTML),旧节点被销毁、新节点被挂载,中间没有“过渡帧”可插值。
-
display: none、visibility: hidden等离散属性无法过渡,浏览器不计算中间值 - 改
:root变量再靠background-color: var(--bg)触发过渡?变量本身不可动画,transition声明在:root上完全无效 - 手动加类名 +
@keyframes模拟?必须自己管理生命周期(比如连点时旧动画未结束就触发新动画),极易出现闪屏、卡顿或静默失败
startViewTransition() 必须同步更新 DOM
API 不是“加个动效”的装饰层,而是强制你把 DOM 变更包裹进回调函数里,且更新必须同步完成。异步加载、延迟插入、状态驱动的渲染周期都会导致失败。
- ✅ 正确:点击后立刻执行
document.body.replaceChildren(...)或document.documentElement.classList.toggle() - ❌ 错误:先
await fetch(),再innerHTML = data—— 报InvalidStateError或静默跳过过渡 - ⚠️ React/Vue 用户注意:不能写
setState({ page: 'next' })然后等框架异步更新;必须在回调里调用forceUpdate或用flushSync(React)/nextTick(Vue)确保 DOM 已同步变更
::view-transition-old 和 ::view-transition-new 的命名规则
浏览器自动捕获 DOM 变更前后的快照,并生成伪元素。要控制特定元素的过渡行为,必须显式设置 view-transition-name,且名称需全局唯一(空格、大写字母、特殊字符均不合法)。
立即学习“前端免费学习笔记(深入)”;
- HTML 中:
<img src="hero.jpg" style="max-width:90%" alt="怎样用CSS新特性实现跨页面的视图过渡动效?" > - CSS 中:
::view-transition-old(hero)对应旧快照,::view-transition-new(hero)对应新快照 - 不设
view-transition-name的元素会归入root分组,统一走::view-transition-old(root)动画 - 多个同名元素?只取第一个,其余被忽略 —— 所以列表项必须用动态名,例如
view-transition-name: item-${id}
兼容性与降级必须手动处理
目前仅 Chromium 111+、Firefox 123+、Safari 17.4+ 支持,且 Safari 对命名过渡支持不完整。不能依赖 @supports (view-transition: none) 全自动降级。
- 检测方式:
if ('startViewTransition' in document),不是if (CSS.supports('view-transition', 'none')) - 降级逻辑必须包裹在条件判断里,比如 fallback 用
opacity+transform的 CSS 动画,但需确保不和视图过渡冲突 -
::view-transition全局样式里不要写animation-duration,它已被废弃;应写在::view-transition-old()和::view-transition-new()规则里
最易被忽略的一点:视图过渡不是“让页面动起来”,而是“让状态变化可感知”。如果 DOM 更新逻辑本身有延迟、抖动或副作用(比如未清理定时器、未取消网络请求),过渡动画只会放大这些问题。先保证变更干净、确定、同步,再加动效。


















