占位结构必须在页面初始html中存在或加载阶段插入,使用visibility:hidden+opacity:0控制显隐,配合fixed定位和will-change强制gpu合成,禁用display:none,mpa下不可复用view transitions api。

页面跳转时 DOM 瞬间销毁,占位结构必须提前挂载
浏览器执行 window.location.href 或表单提交跳转时,当前页面 DOM 会立即被卸载,所有 JS 上下文、CSS 类、动画状态全部清空。所谓“占位结构”,不是跳转后靠 JS 插入的,而是在跳转触发前就已存在于 DOM 中、且能独立撑起视觉过渡的静态元素。
常见错误是:监听点击后才 document.createElement('div') 并 append,再设 opacity: 0 → 1 —— 这个 div 根本来不及渲染就被销毁了,transition 压根没机会启动。
- 占位结构(如
.cd-cover-layer、body::before)必须在页面初始 HTML 中就存在,或在加载阶段就插入并设好初始样式 - 它不能依赖 JS 动态生成后再参与过渡;否则快照拍不到,View Transitions API 也识别不了
- 推荐用伪元素(
body::before)或固定位置的div,避免影响正常文档流,也绕过 JS 执行时机问题
遮罩层必须用 visibility: hidden + opacity: 0,禁用 display: none
很多方案试图用 display: none 隐藏遮罩层,跳转时切为 display: block 再加 transition —— 这完全无效。display 切换不可过渡,浏览器连动画帧都不会生成。
正确做法是让遮罩层始终在 DOM 中、占据空间、可绘制,仅靠视觉属性控制显隐:
- 初始态:
visibility: hidden; opacity: 0; pointer-events: none; - 过渡触发时移除
visibility: hidden,只动opacity和transform - 确保它有明确宽高与定位(
position: fixed+width/height),否则重排会导致动画卡顿 - 若需全屏覆盖,优先用两个各占
50vh的伪元素(body::before/body::after),比 JS 插入更可靠
占位结构的 z-index 与图层顺序必须手动控制
过渡过程中旧页 DOM 已销毁,新页尚未渲染,此时视觉上只能靠占位结构“接住”用户视线。如果它的层级被其他元素(比如 fixed 导航栏、弹窗)盖住,就会出现内容闪现或遮罩失效。
关键点不在“加 z-index”,而在“锁定合成层”:
- 给占位结构加
will-change: opacity, transform;,强制浏览器提前创建独立图层 - 确保它在
body下直接子级,或用position: fixed脱离文档流,避免被 flex/grid 容器的z-index规则干扰 - 不要依赖父容器的
z-index传递——fixed 元素的堆叠上下文是独立的,必须自身设值(如z-index: 9999) - 用 DevTools 的 Layers 面板确认该元素是否进入 GPU 合成层;没进的话动画大概率掉帧
MPA 场景下无法复用 View Transitions API 的占位逻辑
有人尝试把单页中 document.startViewTransition() 的写法套到 MPA 跳转里,比如在 click 回调里包裹 window.location.href = 'page2.html' —— 这不会生效。View Transitions API 只捕获同步 DOM 更新,不拦截导航事件,也不跨 document 生命周期。
MPA 的占位结构和 View Transitions 的 ::view-transition-old 是两套机制,不能混用:
- View Transitions 的“旧视图”依赖当前 document 的 DOM 快照,跳转后整个 document 重建,快照失效
- MPA 占位结构本质是“视觉补丁”,靠 CSS 伪元素或预置 DOM 模拟过渡感,与 JS 生命周期解耦
- 如果你用的是现代框架(如 Astro、Eleventy),可在构建时注入统一占位模板,而不是 runtime 动态判断
真正难的不是写几行 transition,而是让遮罩在页面卸载前完成首帧渲染,并在新页白屏期稳稳撑住界面——这要求结构必须静态、样式必须内联或早于 JS 加载、z-index 必须足够高且不被覆盖。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











