安卓 webview 中输入框被遮挡的根源是软键盘弹出导致视口高度变化,但 absolute 元素依赖的锚点容器高度未及时更新;需用 min-height: 100dvh 或 js 监听 focusin 后 settimeout 读取 visualviewport.height 动态设置父高,并避免 transform/overflow:hidden 等干扰结构。

position: absolute 输入框被遮挡,不是定位写错了
绝对定位本身没问题,问题出在它依赖的「锚点容器」高度失效。安卓 WebView 中 window.innerHeight 会随软键盘弹出而缩小,但 position: absolute 元素仍按父容器当时的 getBoundingClientRect().bottom 计算位置——而这个值在 focusin 触发时还没更新,导致元素卡在键盘下方。
为什么用 min-height: 100vh 还是压不住
因为 vh 单位在多数安卓 WebView(尤其旧版)中不响应键盘弹出,它始终基于初始视口高度。即使你写了 min-height: 100vh,父容器实际渲染高度仍没变,absolute 子元素自然无法“感知”键盘已占位。
- 别用
height: 100vh,它在键盘弹出后会塌陷;必须用min-height: 100dvh(Chrome 105+、部分安卓新版 WebView 支持) - 老安卓 WebView 不支持
dvh?那就得靠 JS 监听focusin后用setTimeout(() => {}, 0)等重排完成,再读visualViewport?.height动态设父容器高度 - 如果父容器本身用了
transform或overflow: hidden,getBoundingClientRect()返回的坐标就不可靠,且无任何报错提示
监听 focusin 时取不到真实 bottom 值
直接在 focusin 回调里读 inputEl.getBoundingClientRect().bottom 是错的——此时键盘刚触发、DOM 尚未重排,返回的是键盘弹出前的坐标。结果就是计算出的 bottom 偏小,输入框仍被盖住。
- 必须加
setTimeout(() => { /* 取坐标 */ }, 0),确保浏览器完成视觉重排后再读值 - 计算方式要用
window.innerHeight - inputRect.bottom,而不是硬编码bottom: 60px - 多个输入框共用同一底部区域?得用全局变量记录当前激活的
inputEl,避免焦点快速切换时状态错乱 - blur 后要立刻清除 inline
top/bottom样式:el.style.removeProperty('top')和el.style.removeProperty('bottom')
最容易被忽略的结构陷阱
所有方案都默认你的页面结构是“干净”的:没有 transform 父级、没有 fixed 外层容器、没有 overflow: hidden 截断滚动链。一旦存在这些,getBoundingClientRect()、scrollIntoView()、甚至 position: sticky 都会静默失效——既不报错,也不工作。
尤其是微信安卓版,它用的是系统 WebView,对 scroll-margin-bottom 和 env(keyboard-inset-bottom) 完全不识别,且 resize 事件延迟严重、触发率极低,根本不能当入口用。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











