opacity单独使用会导致“点不动”或“盖不住”,因元素仍占布局空间、响应事件且可能被截断;可靠全屏遮罩需同时处理fixed定位、100vw/vh尺寸、高z-index、pointer-events分层及visibility+opacity联动过渡。

直接用 opacity + transition 能实现淡入淡出,但全屏遮罩要真正可靠,必须同时处理定位、事件穿透、过渡时机三件事;缩放动画则必须用 clip-path 或 transform,且 Safari 下不加 -webkit-clip-path 和硬件加速会闪动或跳帧。
为什么 opacity 单独用会“点不动”或“盖不住”
只设 opacity: 0 不等于隐藏交互——元素仍占空间、响应点击、可能被 overflow: hidden 截断。常见表现:点关闭按钮没反应、滚动后遮罩错位、iOS 地址栏收缩时漏白。
-
position: fixed; top: 0; right: 0; bottom: 0; left: 0;是底线,不能用absolute挂在某个父容器里 - 尺寸必须用
width: 100vw; height: 100vh;,100%在 body 有 padding 或页面 zoom 时会失效 -
z-index至少设到9999,真实项目里常被弹窗、广告位压住 -
pointer-events: none;加在遮罩层本身,内部按钮再用pointer-events: auto;单独放开
visibility + opacity 联动才是淡入淡出的稳解
display: none 根本不能过渡,浏览器无法插值;visibility 控制是否参与渲染流和事件分发,opacity 控制透明度,两者都支持平滑过渡,语义清晰。
- 初始状态写死:
visibility: hidden; opacity: 0; transition: visibility 0.1s steps(1, end), opacity 0.3s ease-out; - 显示时加类(如
.show):visibility: visible; opacity: 1; - JS 监听
transitionend时务必过滤:if (e.propertyName === 'opacity'),否则visibility和opacity各触发一次 - 别在
visibility: hidden后立刻remove()元素——DOM 消失会导致transitionend永远不触发
clip-path 缩放动画在 Safari 必须加前缀和硬件加速
用 clip-path: circle() 做中心缩放,Safari 默认原点在左上角,不显式指定圆心就会偏移;且部分版本不触发硬件加速时动画会卡顿或跳帧。
立即学习“前端免费学习笔记(深入)”;
- 起始状态必须写:
clip-path: circle(0 at 50% 50%); -webkit-clip-path: circle(0 at 50% 50%); - 过渡声明放在遮罩容器上:
transition: clip-path 0.6s cubic-bezier(0.22, 0.61, 0.36, 1), -webkit-clip-path 0.6s cubic-bezier(0.22, 0.61, 0.36, 1); - 结束状态保险值用
circle(150% at 50% 50%),确保高 DPR 屏幕也完全覆盖 - 父容器加
transform: translateZ(0)或will-change: clip-path触发硬件加速 - JS 切换类前,建议等
requestAnimationFrame下一帧再操作,避免样式未就绪导致动画不触发
容易被忽略的兼容性细节
这些不是“理论上可行”,而是上线后立刻暴露的问题:移动端 touchstart 时遮罩若还没 fully visible,点击会穿透;iOS Safari 滚动后可能重置 clip-path 状态;transition: all 会意外拖慢整个过渡,尤其当遮罩内含 transform 动画时。
最易漏的是 pointer-events 分层配置和 transitionend 的 propertyName 过滤——前者导致用户点不到背后按钮,后者让回调执行两遍、状态错乱。


















