最稳方案是用 transition 配合 transform 或 opacity,单页状态切换优先用 View Transitions API;transition 失效主因是属性不可插值、初始值未声明或 DOM 更新不同步;View Transitions API 失效多因快照前元素不可见或 view-transition-name 不匹配。

直接说结论:用 transition 配合 transform 或 opacity 最稳,别碰 display 和 height: auto;单页内状态切换优先用 View Transitions API,但必须确保 DOM 同步更新且 view-transition-name 成对唯一。
transition 加了没反应?先查这三件事
常见现象是 hover 或 JS 切 class 后毫无动画,不是浏览器不支持,而是过渡根本没被触发:
-
transition只对可插值、有明确起止值的属性生效——opacity、transform行,display、height: auto、z-index不行 - 基础样式里必须显式声明初始值,比如要过渡
opacity,就得先写opacity: 1,不能只在:hover或 class 里写opacity: 0 - JS 直接改
element.style.opacity = 0再改回1,中间没留重排机会,动画会跳过;加一句void element.offsetWidth强制同步布局就能救回来
View Transitions API 动画消失?大概率卡在这两个点
这个 API 不是“加个属性就动”,它依赖浏览器拍两帧快照(旧状态 + 新状态),拍歪了就只剩淡入:
-
document.startViewTransition()必须包裹**同步 DOM 更新操作**,比如container.innerHTML = newHTML或container.replaceChildren(newNode);里面塞await fetch()或setTimeout就失效 -
view-transition-name必须在新旧元素上**完全一致**(大小写、空格、动态 ID 都算错),且元素得已挂载到document中——刚createElement('div')没append()就设该属性,快照捕获不到 - 旧元素在过渡开始前不能是
display: none、visibility: hidden或opacity: 0,哪怕opacity: 0.001也比彻底隐藏强,否则快照里没它
页面级切换(如 SPA 路由)怎么加过渡
history.pushState 不触发重绘,CSS 动画类名加了也白加,得手动控制时机:
立即学习“前端免费学习笔记(深入)”;
- fetch 加载新 HTML 片段后,先清空容器、
void container.offsetWidth强制重排,再插入新内容并添加入场 class(如animate-in) - CSS 里用
transform+opacity做位移+透明变化,避免触发布局重排;iOS Safari 上记得加will-change: transform和backface-visibility: hidden防闪烁 - 用
transitionend事件监听动画结束,而不是靠setTimeout,否则缩放设置、GPU 就绪延迟都会导致偏差
最易被忽略的其实是“可绘制状态”——很多动画失效,不是代码写错,而是旧元素在快照前就被设成不可见或未挂载。View Transitions API 尤其敏感,它不关心你逻辑多漂亮,只认“此刻能否拍到两张清晰的图”。



















