设置 height: 100vh 会导致 flex 布局在输入法弹出时变形,因其按初始视口高度计算且 ios safari 等不更新 vh 或触发 resize;应改用 min-height/max-height: 100dvh + overflow-y: auto,并对关键区域设 flex-shrink: 0 或 flex: 0 0 auto,配合 visualviewport.resize 监听与防抖处理。

为什么设置 height: 100vh 会让 Flex 布局在输入法弹出时变形
因为 height: 100vh 是按“初始视口高度”计算的固定值,而 iOS Safari 和部分 Android WebView 在软键盘弹出时不会更新 vh 单位,也不会触发 resize 事件。结果就是:Flex 容器仍按全屏高度渲染,但实际可视区域被压缩,导致内容被截断、底部输入框被遮挡、flex: 1 区域塌陷或滚动错乱。
用 min-height + max-height 替代 height 的实操要点
直接替换掉所有 height: 100vh,改用更弹性的约束:
-
min-height: 100dvh—— 确保内容少时也能撑满当前可见视口(Chrome 105+、Safari 16.4+ 支持) -
max-height: 100dvh—— 防止内容过多时容器无限拉伸,挤压子项 -
overflow-y: auto—— 让内部可滚动,而不是靠 flex 压缩来“适应”变小的视口
例如登录页容器:
.container {
display: flex;
flex-direction: column;
min-height: 100dvh;
max-height: 100dvh;
overflow-y: auto;
}
.header { flex-shrink: 0; }
.main { flex: 1; overflow-y: auto; }
.footer { flex-shrink: 0; }
不支持 dvh 时 JS 降级必须监听 visualViewport.resize
仅靠 height: 100vh 降级是无效的——它依然会卡在初始高度。真正起作用的是动态绑定当前视觉视口:
- 优先用
window.visualViewport?.height,它在 iOS 上比window.innerHeight准确得多 - 必须监听
visualViewport.resize,不能只靠focus/blur或resize(iOS 不触发后者) - 避免在
focus回调里立即读取高度——键盘展开有延迟,建议加setTimeout(..., 50)防抖 - 设完高度后,对
.main区域手动scrollTo(0, 0),防止 iOS 滚动锚点残留
flex-shrink: 0 不是万能解,但它能守住关键区域
即使高度动态修正了,子项仍可能因空间不足被压缩变形。这时要锁定不可压缩的部分:
- 头部、底部、输入框容器等固定功能区,必须加
flex-shrink: 0 - 不要只写
flex-shrink: 0,搭配min-height或显式height(如height: 44px)才真正防塌陷 -
flex: 0 0 auto比单独写flex-shrink: 0更明确,表示“完全不伸不缩” - 注意:如果父容器本身高度没控住(比如用了
height: 100%而非dvh),flex-shrink: 0也救不了整体布局
visualViewport.height 并不会立刻回到原始值,常有 100–200ms 延迟。这意味着你不能依赖单次 resize 事件就重置样式,得结合阈值判断 + 防抖,否则会出现“闪一下再恢复”的抖动。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











