min-h-[100dvh]是解决软键盘弹出时布局塌陷的可靠方案,因其动态响应可视区域变化;需配合flex flex-col、flex-1及flex-shrink-0使用,并删除meta中height=device-height等干扰项。

直接用 100vh 在移动端软键盘弹出时必然塌陷,这不是 Tailwind 的问题,而是浏览器对视口高度的计算逻辑变了——iOS Safari 根本不更新 vh 值,Android Chrome 表现也不一致。必须换用更可靠的单位或策略。
为什么 min-h-screen 和 h-screen 在键盘弹出时都不可靠
min-h-screen 编译为 min-height: 100vh,h-screen 是 height: 100vh,两者都依赖 vh 单位。而键盘弹出后:
- iOS Safari 的
100vh仍按初始视口(未弹键盘时)计算,导致容器过高、底部留白或内容被截断 - Android 部分 WebView(如华为、UC)甚至不支持
vh,直接忽略整条规则 -
min-h-screen虽比h-screen容错稍好,但一旦父容器没设flex或高度来源,flex-grow就无空间可分,主内容区照样塌成一条线
优先改用 min-h-[100dvh] 并配 flex 布局
dvh(dynamic viewport height)是真正随键盘伸缩的单位,iOS 16.4+ 和 Android Chrome 109+ 已稳定支持。Tailwind 3.3+ 可直接用 min-h-[100dvh] 替代 min-h-screen:
- 必须配合
flex flex-col使用,否则min-h-[100dvh]只设最小高度,不触发子项弹性分配 - 主内容区要加
flex-1(即flex: 1 1 0%),但更推荐显式写flex-grow flex-shrink-0 min-w-0,避免文字溢出拉宽容器 - 底部固定区域(如提交按钮)必须加
flex-shrink-0,否则键盘弹出时会被 flex 压缩变形 - 不要给
html或body设h-full或min-h-full,这会干扰dvh行为
兜底方案:focus/blur 切换 class 控制高度
CSS 无法感知键盘,但输入框聚焦是最强信号。用 JS 监听 focusin 和 blur 动态切 class 是目前最可控的兼容手段:
立即学习“前端免费学习笔记(深入)”;
- 在
focusin后用setTimeout(() => {...}, 0)读取visualViewport?.height,再设置body的style.height为该值 - 别用
window.innerHeight—— iOS 键盘收起后它可能延迟更新,造成回弹错位 - 必须在
blur后恢复auto高度,否则页面滚动时定位异常 - 多个输入框共用同一底部栏时,需用
document.activeElement统一判断焦点状态,避免重复切换
容易被忽略的边界点
哪怕用了 100dvh + flex,这几个细节仍会导致塌陷重现:
-
meta viewport里写了height=device-height—— 这个参数会让所有vh类单位失效,必须删掉 - 侧边栏或弹窗用了
fixed定位但没脱离文档流,其父容器仍占位,撑高根容器引发滚动条,间接破坏flex高度计算 - 响应式断点切换时(如
md:flex-row→flex-col),没重置order或补min-h-[100dvh],小屏下又退回到vh陷阱 - 测试时只看 DevTools 的模拟器,但真机上 UC、华为浏览器连
dvh都不识别,得用env(safe-area-inset-bottom)配合 padding 底部预留

















