抽屉遮罩层必须用 position: fixed,因其能始终锚定视口、不随滚动偏移、不受父容器 overflow 或 transform 限制;若用 absolute 则依赖定位祖先,易被截断或错位,须配合 top/right/bottom/left: 0 及 rgba 背景确保完整覆盖与内容清晰。

抽屉遮罩层为什么必须用 position: fixed?
因为抽屉(drawer)通常从页面边缘滑出,而遮罩(mask)需要覆盖整个可视区域,包括滚动后的内容。如果用 position: absolute,遮罩会随父容器定位,一旦父元素有 overflow: hidden 或不是视口级容器,遮罩就盖不全;用 fixed 才能真正“钉”在视口上,不受滚动和嵌套影响。
常见错误:把遮罩放在 drawer 内部、或和 drawer 同级但父容器设置了 transform —— 这会创建新的定位上下文,导致 fixed 相对这个新容器定位,遮罩变小或偏移。
- 遮罩元素必须是
body直接子节点,或至少确保其祖先没有transform、perspective、filter等触发新层叠上下文的属性 - 样式至少包含:
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 999; - 别用
100%代替100vw/100vh—— 在 iOS Safari 中,100%高度可能只等于初始视口高度,滚动后遮罩露底
pointer-events: none 和 pointer-events: auto 怎么配着用?
遮罩默认要拦截点击穿透到背后内容,但又不能挡住抽屉本体的交互(比如抽屉里的按钮、输入框)。最稳妥做法是:遮罩本身设 pointer-events: auto,抽屉容器设 pointer-events: auto,同时确保抽屉在遮罩上方(更高 z-index)。
容易踩的坑是给遮罩加 pointer-events: none——这会让点击直接穿过遮罩落到页面底层,用户点不到抽屉,也关不掉它。
立即学习“前端免费学习笔记(深入)”;
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 遮罩层:必须
pointer-events: auto,并绑定click事件用于关闭抽屉 - 抽屉层:必须
pointer-events: auto,且z-index高于遮罩(如遮罩z-index: 999,抽屉设z-index: 1000) - 如果抽屉里有下拉菜单、浮层等子浮层,它们的
z-index要比抽屉更高,否则会被抽屉的overflow: hidden截断
遮罩透明度和过渡动画怎么不卡顿?
用 opacity + transition 最简单,但要注意:opacity 动画本身是可硬件加速的,前提是不能和会触发重排的属性(如 height、width)混用在同一 transition 中。遮罩不需要尺寸变化,只做淡入淡出,所以只过渡 opacity 就够了。
别写成 transition: all 0.3s —— 这会让浏览器监控所有属性变化,增加开销;iOS 上还可能因触发重绘导致闪烁。
- 推荐写法:
transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1); - 初始状态设
opacity: 0; visibility: hidden;,显示时改为opacity: 0.5; visibility: visible;——visibility防止遮罩占位或响应事件 - 避免在遮罩上用
background: rgba()做半透,改用background: #000; opacity: 0.5,更利于 GPU 加速
移动端点击穿透问题怎么防?
iOS Safari 在快速连续点击遮罩和抽屉时,可能出现“穿透”:第一次点击遮罩关闭抽屉,第二次点击却触发了遮罩下方原本被盖住的按钮。这不是 bug,而是系统对快速点击的合成优化导致的事件冒泡残留。
根本解法不是阻止默认行为,而是让遮罩在关闭过程中短暂禁用交互,并配合 CSS 层级隔离。
- 关闭抽屉时,先移除遮罩的
click监听器,再执行动画;动画结束后再清理 DOM - 给遮罩加
touch-action: none,防止 iOS 对遮罩区域做手势识别干扰 - 确保遮罩和抽屉都设置
will-change: opacity(仅动画期间),提示浏览器提前准备图层 - 不要依赖
preventDefault()拦截遮罩的touchstart—— 它会影响滚动体验,且无法彻底解决穿透
position 上下文、pointer-events 配合、以及关闭瞬间的事件生命周期处理——这三个地方一松动,遮罩就漏风。


















