position: fixed + inset: 0 + display: flex 是跨浏览器稳定实现模态框遮罩层的唯一可靠起点,因 inset: 0 真正锚定视口四边,避免 safari/webview 下 100vh/dvh 异常、软键盘塌缩及父容器未撑满导致的漏边问题。

直接用 position: fixed + inset: 0 + display: flex 是唯一能跨浏览器稳定落地的起点,其他写法在 Safari、WebView 或软键盘弹出时大概率错位或塌缩。
遮罩层必须用 inset: 0 而非 width/height: 100%
因为 100% 是相对父容器计算的,而遮罩层常被插入到 body 底部——如果 body 没撑满视口(比如没设 min-height: 100vh),遮罩就会漏边。更糟的是,某些 Android WebView 对 100vw/100vh 解析异常,inset: 0 才是真正锚定视口四边的可靠写法。
SCSS 中建议这样封装:
.modal-overlay {
position: fixed;
inset: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
background-color: rgba(0, 0, 0, 0.6);
pointer-events: auto;
&.is-hidden {
display: none;
}
}
-
pointer-events: auto是为了后续可给遮罩加「点击关闭」逻辑;若只做纯遮罩,可改为pointer-events: none,再单独给弹窗设pointer-events: auto - 别用
opacity控制透明度——它会让内部所有子元素(包括按钮、图标)一起变淡 -
z-index: 1000是底线值,实际项目中得检查第三方库(如 Ant Design 默认用1050),建议统一用 CSS 变量管理:--z-modal-overlay: 1000
.modal-content 内部用 Grid 划分区域,别在遮罩层上套 Grid
很多人想在 .modal-overlay 上直接加 display: grid 和 place-items: center,这会导致 Safari 塌陷、滚动错位、backdrop-filter 失效——Grid 不处理定位,它只划分容器内部空间,而 fixed 元素的尺寸在 iOS 上本就不稳定。
正确做法是把 Grid 用在弹窗本体内部:
.modal-content {
display: grid;
grid-template-rows: max-content 1fr max-content;
row-gap: 1rem;
max-width: 90vw;
width: fit-content;
min-width: 320px;
background: #fff;
border-radius: 8px;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.modal-header { grid-row: 1; }
.modal-body { grid-row: 2; overflow-y: auto; min-height: 0; }
.modal-footer { grid-row: 3; }
-
min-height: 0在.modal-body中必不可少,否则 Safari 下1fr不收缩,内容溢出不可滚动 -
max-content比auto更可控,避免标题/按钮因内容过长意外撑开整行 - 别给
.modal-content设position: absolute——它已是flex子项,无需脱离文档流
响应式与移动端兼容的关键 SCSS 变量和 fallback
iOS Safari 软键盘弹出时,100vh 会骤降,导致遮罩高度塌缩;Chrome/Safari 新版支持 dvh,但得 fallback。
推荐这样写:
.modal-overlay {
// 主力单位:动态视口高度
min-height: 100dvh;
// 降级:标准视口高度
min-height: 100vh;
// 再兜底:防止极端情况(如横屏切竖屏瞬间)
min-height: -webkit-fill-available;
}
-
100dvh是动态视口单位,软键盘弹出时不重算,但仅 Chrome 105+/Safari 16.4+ 支持 -
-webkit-fill-available是 Safari 专属兜底,能撑满当前可用高度 - 别在
.modal-overlay上加overflow: hidden——某些安卓 WebView 会裁剪动画或遮罩边缘
最易被忽略的一点:遮罩层的 background-color 必须用 rgba() 字符串格式,且不能被祖先元素的 transform、filter 或 will-change 截断定位参考系——这些属性会创建新层叠上下文,让 fixed 相对于该祖先而非视口。检查 DOM 结构是否干净,比调样式更重要。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











