position: fixed加inset: 0是最稳写法,因其天然锚定视口、不随滚动偏移、不受父容器overflow或transform截断,且inset: 0语义清晰、不易漏边、不依赖易跳变的100vh。

为什么position: fixed加inset: 0是最稳写法
因为position: fixed天然锚定视口,不随滚动偏移、不被父容器overflow或transform截断;inset: 0等价于top: 0; right: 0; bottom: 0; left: 0,语义清晰、不易漏边,且不依赖100vh——后者在 iOS Safari 地址栏收放时会跳变,导致遮罩底部留白或撑出滚动条。
常见错误:
- 只写position: fixed但没设定位值,元素缩成一个点(默认top: auto; left: auto)
- 用position: absolute,结果被最近的定位祖先框住,滚动后消失
- 用width: 100vw; height: 100vh,在有垂直滚动条的页面中100vw包含滚动条宽度,引发水平溢出
z-index和挂载位置必须一起处理
遮罩层再“全屏”,也得能盖住一切。光靠position: fixed不够,z-index必须显式设高(比如z-index: 99999),否则容易被 sticky 导航栏、地图 SDK 控件或 iframe 盖住。
更关键的是挂载位置:
- 别把遮罩塞进某个div.modal里,尤其当外层有transform: translateZ(0)或filter时,会创建新层叠上下文,让z-index失效
- 正确做法是用 JS 动态调用document.body.append(overlayEl),确保它直接挂在下
- 若项目用 React/Vue,别在组件内部渲染遮罩 DOM,而应通过createPortal或Teleport丢到body末尾
背景透明与点击穿透的配合逻辑
遮罩要“看得见又点不着”,靠两个属性分工:
- 背景用background-color: rgba(0, 0, 0, 0.5),不是opacity: 0.5——后者会让内部搜索框、按钮也变模糊
- 点击穿透靠pointer-events: none作用于遮罩自身,但子元素(如<input>、<button></button>)必须显式恢复pointer-events: auto,否则事件路径被阻断,点不到里面内容
注意:
- pointer-events: none只是“不主动拦截”,不代表自动透传;子元素若没设auto,就真点不中
- 若遮罩内需响应点击(比如点击空白处关闭),监听click时要检查event.target === event.currentTarget,避免误触弹窗内容
移动端滚动穿透和高度错位怎么防
iOS Safari 是重灾区:遮罩开着时还能滚底层、地址栏收起后遮罩错位、软键盘弹出导致底部留白。根本原因不是 CSS 写错了,而是
没锁死、视口没兜底。实操建议:
- 遮罩激活时,给body加overflow: hidden(仅靠pointer-events: none挡不住滚动)
- 加body { overscroll-behavior: contain; }阻止惯性滚动透出
- 不要信user-scalable=no(现代浏览器已忽略),改用touch-action: none在遮罩层上禁用触摸行为
- 若页面本身可缩放,fixed元素可能因 DPI 缩放偏移,此时flex居中比top: 50%; transform: translateY(-50%)更可靠
真正难的不是写几行 CSS,而是理解fixed在不同上下文中的行为边界:它不总是锚定视口,z-index不总是在全局生效,pointer-events不是开关而是路径控制。这些细节一旦漏掉,遮罩就会在某台 iPhone 或某个 WebView 里突然失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











