应使用100dvh替代100vh,并配合focusin/blur事件监听及absolute+relative定位方案。因软键盘弹出时vh不更新、resize不触发,导致输入框被顶起或消失;100dvh动态适配可视高度,再通过js监听聚焦与失焦调整布局,辅以绝对定位避免fixed锚点失效。

直接用 height: 100vh 或单纯靠 flex 布局无法避免输入框被顶起——这不是布局写错了,是浏览器把 vh 锁死在初始视口高度,而软键盘弹出时根本不更新它。
为什么 flex + 100vh 在键盘弹出时会失效
iOS Safari 和多数安卓 WebView(尤其是微信内置浏览器)在软键盘唤起后,window.innerHeight 不变、resize 事件不触发,但实际可视区域被压缩。此时 height: 100vh 还按原始高度撑开容器,中间 flex: 1 的内容区被强行挤压或截断,底部输入框直接消失或卡在屏幕外。
- 常见现象:页面加载正常,
input聚焦后,底部输入框“跳”到屏幕中间或完全不可见 -
min-height: 100vh比height: 100vh稍好,但仍无法响应键盘变化 - 即使加了
overflow-y: auto,滚动也常无法自动定位到聚焦的输入框
优先用 100dvh 替代 100vh,并设 max-height + overflow
100dvh 是动态视口单位,代表“无键盘状态下的完整可视高度”,它不受软键盘影响,且能随安全区域(如 iPhone 底部手势条)自动调整。Chrome 105+、Safari 16.4+ 已原生支持。
- 把所有
height: 100vh改成min-height: 100dvh; max-height: 100dvh; overflow-y: auto - 关键子项(如输入框容器)加上
flex-shrink: 0,防止被 flex 压缩变形 - 必须确保
<meta name="viewport">正确:<meta name="viewport" content="width=device-width, initial-scale=1.0"> - 禁用
maximum-scale=1或固定width=375,否则dvh会退化
安卓 WebView 和老 iOS 必须补 JS 监听 focusin/blur
100dvh 在安卓 WebView(如微信、QQ 浏览器)和 Safari
- 只监听
input和textarea的focusin(不是focus),避免冒泡干扰 - 记录初始
window.innerHeight,聚焦后对比:若差值 > 150px,视为键盘弹出 -
blur后延时 300ms 再恢复高度,给键盘收起留出时间 - 不要依赖
document.body.scrollHeight—— 它在很多安卓机型上根本不变 - 配合
scrollIntoView()或手动window.scrollTo(0, input.offsetTop)滚动到输入框
底部输入框容器别用 fixed,改用 absolute + relative 父容器
哪怕用了 100dvh,如果输入框父容器是 position: fixed,在 iOS 上仍可能错位或消失——因为 fixed 锚定的是被键盘篡改过的 visualViewport。
- 根容器设
position: relative; min-height: 100vh(作为 fallback) - 输入框容器用
position: absolute; bottom: 0; width: 100% - 在
focusin后用setTimeout(() => { ... }, 0)获取真实input.getBoundingClientRect().bottom - 计算
bottom值:${window.innerHeight - inputRect.bottom}px -
blur后立刻切回bottom: 0,否则滚动时元素会脱离
真正稳定的做法从来不是“修一个属性”,而是三者叠加:100dvh 扛住现代浏览器,focusin/blur 补安卓 WebView,absolute + relative 彻底绕开 fixed 的锚点失效问题。任何单点方案,在真机混合环境下都大概率漏掉某类机型或某个触发时机。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











