根本原因是浏览器将地址栏高度计入100vh且不动态更新,应改用min-h-[100dvh]并配合flex flex-col、flex-1及flex-shrink-0布局,删除meta中height=device-height,旧版iOS需JS动态设--vh变量兜底。

移动端 100vh 在 Tailwind 中“塌陷”或“短一截”,根本不是类名写错,而是浏览器把地址栏高度算进视口、但不随滚动动态更新 —— 你写的 h-screen 或 min-h-screen 编译出来就是 height: 100vh 或 min-height: 100vh,它卡死在初始视口高度上,一滑页面就露底、一弹键盘就留白。
用 min-h-[100dvh] 替代 min-h-screen
现代方案首选 min-h-[100dvh],它是真正响应地址栏收放和软键盘弹起的单位。iOS 16.4+ 和 Android Chrome 109+ 已稳定支持,Tailwind 3.3+ 可直接使用。
-
min-h-[100dvh]是最小高度,不是固定高度 —— 它只保证容器不低于当前可视区域,不会强制撑满导致底部被遮 - 必须搭配
flex flex-col布局,否则子元素无法弹性分配剩余空间 - 别混用
h-screen和min-h-[100dvh]:前者会覆盖后者,造成降级失效 - 如果项目需兼容 Safari 15.x 及更早,
@supports (height: 100dvh)必须包裹该声明,否则老浏览器直接忽略整条规则
Flex 布局必须配对写全
光换单位不够,min-h-[100dvh] 只设下限,主内容区要靠 Flex 规则“拉伸填满”。漏掉任意一环,布局立刻塌成一条线。
- 根容器加
flex flex-col,且确保父级(如html、body)没写h-full—— 否则会干扰 dvh 的计算基准 - 主内容区(比如表单或列表)必须加
flex-1,推荐显式写flex-grow flex-shrink-0 min-w-0,避免长文本撑宽容器 - 固定底部(如按钮、TabBar)加
flex-shrink-0,否则键盘弹出时会被压缩变形 - 删掉
里的height=device-height—— 这个参数会让所有vh类完全失效
JS 动态 fallback 要防抖、读对值
当目标设备不支持 dvh(如 iOS 15 或部分安卓 WebView),就得用 JS 读取真实可视高度兜底。但直接用 window.innerHeight 在 iOS 上有延迟,键盘收起后值滞后,会导致回弹错位。
- 监听
resize和scroll(iOS 地址栏收起时只触发scroll,不触发resize) - 用
requestAnimationFrame或setTimeout(() => {}, 50)防抖,避开高频重排 - 首次渲染前就要执行一次设置,否则首屏闪动或留白
- CSS 中写
min-height: calc(var(--vh, 1vh) * 100),其中1vh是降级兜底值,不是1px - 绝对不要给
body直接设style.height—— 键盘收起后它不自动恢复,后续滚动定位会异常
最容易被忽略的是:哪怕用了 100dvh + flex,只要中间某层容器(比如 )漏了 flex-1,或者侧边栏用了 fixed 但没加 inset-0 和 z-index,整个高度链就断了 —— 此时不是单位问题,是布局流被破坏了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











