纯CSS全屏遮罩动效应使用transform: scale() + opacity,避免display切换、height/max-height动画,并绕开移动端vh塌陷;需动态设置transform-origin、固定定位挂载body下、预加载内容并强制layout。

纯 CSS 实现全屏遮罩展开/收起转场动效,关键不在“能不能做”,而在于**避免用 display 切换、不依赖 height 动画、且必须绕开移动端 vh 塌陷和合成层陷阱**。只要这三点踩准,transform: scale() + opacity 就能跑出顺滑效果。
为什么不能用 height 或 max-height 动画
全屏遮罩不是折叠面板,max-height: 0 → 100vh 看似简单,但实际会触发重排(reflow),尤其在 iOS Safari 中动画卡顿明显;更严重的是,100vh 在地址栏收起时会变大,导致遮罩突然撑高、底部留白甚至滚动条闪现。这不是 bug,是浏览器行为,没法靠 CSS hack 彻底修复。
- 改用
transform: scale(0) → scale(1),全程 GPU 加速,无重排 - 缩放目标尺寸统一写死为
100vw/100vh,不依赖父容器高度 - 初始状态必须是
opacity: 0; transform: scale(0.95),而非display: none—— 否则动画第一帧会跳
transform-origin 必须动态设置才自然
硬写 transform-origin: 50% 50% 会让遮罩从屏幕正中心弹出,脱离用户操作上下文。比如从右上角菜单按钮点开,遮罩却从正中炸开,体验割裂。
- 点击按钮时,用 JS 计算坐标:
const rect = btn.getBoundingClientRect(); const x = rect.left + rect.width / 2 - window.scrollX; - 然后设
overlay.style.transformOrigin = `${x}px ${y}px` - 动画结束后立即重置回
50% 50%,否则后续其他 transform 操作(如平移)会错位 - 别直接用
btn.offsetLeft,它不包含滚动偏移,移动端一滚动就偏
遮罩 DOM 结构和层级必须干净
遮罩层一旦嵌套在 overflow: hidden 或带 transform 的父容器里,就会被裁剪或坐标错乱;同时,pointer-events 和 z-index 不配好,点一下就关不掉或点不动。
- 遮罩元素必须是
position: fixed,且直接挂载在下,不要塞进某个里- 写全
top: 0; right: 0; bottom: 0; left: 0,比width: 100%; height: 100%更稳- 背景用
background-color: rgba(0, 0, 0, 0.5),绝不用opacity—— 否则里面弹窗内容也变透明z-index至少设到9999,并检查是否被 header、广告位等固定定位元素盖住- 确保遮罩本身没被父级设
pointer-events: none,用开发者工具看 computed 样式确认最易被忽略的一点:动画开始前,新内容必须已插入 DOM 且样式就绪。如果先触发
scale动画,再往遮罩里innerHTML塞菜单项,Chrome 会把“插入”和“缩放”压进同一帧,导致首帧空白或文字闪现。正确做法是插入后立刻读一次el.offsetHeight强制 layout,再开动画。 - 写全
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











