100vh在键盘弹出时失效,因其是初始视口高度的静态快照值,ios safari不更新、安卓webview更新不同步;应改用100dvh并配合降级策略。

因为 vh 单位在移动端不是“当前可见高度”,而是浏览器按某个固定时刻的视口尺寸算出的静态像素值;输入法弹出时,视口被压缩,但 vh 不重算,导致元素高度错配——这不是你写错了,是单位机制本身不响应键盘状态。
为什么 vh 在键盘弹出时会“变小”
安卓 WebView 和 iOS Safari 都把 100vh 解析为 document.documentElement.clientHeight 的初始快照值。键盘弹出后,这个值理论上该变,但:
- iOS Safari 根本不更新
documentElement.clientHeight,也不触发resize事件 - 部分安卓浏览器虽更新了 clientHeight,但 CSS 引擎仍沿用旧
vh像素换算结果(即 1vh = Xpx 这个映射不变) - 结果就是:容器还按“全屏高”渲染,但实际可视区域只剩一半,内容被截、
flex: 1区域塌陷、fixed 按钮沉底失效
dvh 能直接替代 vh 吗
能,但有硬限制:100dvh 确实会随键盘弹出实时更新,但它不可被 JS 读取为像素值(getComputedStyle(el).height 返回 100dvh 字符串,不是数字),也不能用于 @media 查询或 calc() 中做数值运算(如 calc(100dvh - 40px) 无效)。
更关键的是兼容性:
- Chrome 105+、Safari 16.4+ 支持
dvh - 旧版 iOS(100vh 静态值
- 所以必须写成
height: 100vh; height: 100dvh;,后者覆盖前者
不用 dvh 时,怎么稳住 Flex 容器高度
核心是放弃“固定高度”,改用弹性约束 + 显式防缩:
- 把
height: 100vh全部换成min-height: 100dvh; max-height: 100dvh; overflow-y: auto; - 对输入框所在区域或底部操作栏,加
flex-shrink: 0或flex: 0 0 auto,防止被 Flex 压缩 - 监听
visualViewport?.addEventListener('resize', handler)(比resize更准,iOS 也支持),配合防抖更新关键区域高度 - 避免在键盘弹出期间依赖
window.innerHeight——它在 iOS 上常返回错误值(比如弹出后仍等于初始高度)
为什么 svh/lvh 不是万能解
100svh 是“工具栏展开时的最小高度”,100lvh 是“工具栏收起时的最大高度”,它们都是固定锚点,不随键盘动态变化:
-
100svh适合底部按钮——确保永远不被地址栏顶起,但键盘弹出后可能留大片空白 -
100lvh适合启动页——追求最大沉浸感,但键盘弹出会把内容顶出可视区 - 它们都不能表达“键盘弹出后剩余可用高度”,所以无法替代
dvh做通用适配
真正难的不是选哪个单位,而是意识到:所有视口单位都绕不开浏览器对“当前视口”的定义分歧——iOS 认为键盘弹出后仍是“同一视口”,安卓却认为它是新视口。这种底层差异,没法靠 CSS 单独填平。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











