用100dvh替代100vh解决iOS键盘弹出后align-items:center失效问题,因Safari中100vh不随键盘收缩更新;遮罩层需position:fixed+inset:0+display:flex并挂载于body直子级,禁用子元素absolute/transform以保障居中逻辑。

直接结论:用 position: fixed + inset: 0 遮罩层 + display: flex 居中弹窗内容,高度单位必须用 100dvh(降级 fallback 到 100vh),同时禁用弹窗子元素的 position: absolute 或 transform —— 否则居中逻辑会被绕过。
为什么 align-items: center 在 iOS 键盘弹出后失效
不是 CSS 写错了,是父容器交叉轴(垂直方向)高度塌陷了。键盘弹出时,Safari 的 100vh 不更新,仍按初始视口算(比如 812px),但实际可视区域只剩 600px 左右,导致遮罩层高度远大于当前可视区,align-items: center 失去可分配空间。
- DevTools 里检查遮罩层高度,若显示为
812px而非当前可视高度,就确认是vh失效 - 别在
body上直接设display: flex—— iOS Safari 和微信 X5 内核会忽略 - 用
min-height: 100vh也不行,它只保底,不提供对齐所需的确定高度 - 必须显式写
height: 100dvh,并加降级:height: 100vh; height: 100dvh;(后者覆盖前者)
position: fixed + inset: 0 是遮罩层唯一可靠写法
不用 top: 0; right: 0; bottom: 0; left: 0,直接用 inset: 0 更简洁,且避免老版本因顺序解析出错。关键是它不依赖任何视口单位,也不受祖先 transform 或 filter 截断。
- 遮罩层必须挂载在
直接子级,别嵌套在某个.app容器里 - 加
background-color: rgba(0, 0, 0, 0.5),别用opacity,否则弹窗内容也变透明 - 打开弹窗时务必加
body { overflow: hidden; },关闭时还原,否则键盘弹出时底层可能滚动 - 遮罩层自身设
display: flex; justify-content: center; align-items: center;,弹窗作为其**直接子元素**即可居中
弹窗内容区要防键盘顶起、防模糊、防错位
一旦弹窗内部有 <input>,就得让它在键盘弹出后仍可见。纯 CSS 方案比 JS scrollIntoView 更稳,但需规避几个渲染陷阱。
立即学习“前端免费学习笔记(深入)”;
- 弹窗自身禁用
position: absolute或transform—— 它们会让元素脱离 flex 流程,align-items彻底无效 - 给输入框加
scroll-margin-bottom: 60px,前提是它在可滚动容器内(比如遮罩层设overflow-y: auto+min-height: 100dvh) - 删掉所有
will-change: transform和backface-visibility: hidden—— 它们在 iOS Safari 中易引发文字模糊或定位跳动 - 如果项目需兼容 iOS 15.6 等老系统,加一行 JS 补偿:
document.documentElement.style.height = window.visualViewport?.height + 'px';,并在visualViewport.addEventListener('resize', ...)中更新
真正难的不是写出能居中的代码,而是判断哪个环节在键盘弹出后悄悄失效:是遮罩层高度没更新?是输入框被 transform 拉偏了?还是 overflow: hidden 漏加导致底层滚动干扰了视觉锚点?每次调试先看 DevTools 里遮罩层的实际高度值,比猜样式更直接。


















