应避免使用100vh而改用100dvh或JS动态适配:Safari/安卓WebView中vh不随软键盘弹出更新,导致输入框被遮挡;fixed定位在iOS易失效;推荐scroll-margin-bottom+absolute布局及逐层降级策略。

软键盘弹出时 vh 不更新导致输入框被遮挡
移动端 Safari 和部分安卓 WebView 中,软键盘弹出会压缩视口(viewport),但 vh 单位**不会实时重算**——它始终基于初始视口高度。所以用 height: 100vh 布局的页面,键盘弹起后底部 input 很可能被盖住,且滚动失效。
实操建议:
- 别依赖
vh做「全屏高度」布局,尤其当页面底部有固定输入框时 - 改用
min-height: 100dvh(dvh是动态视口高度,Safari 16.4+、Chrome 105+ 支持) - 兼容老版本?用 JS 监听
resize事件 +window.visualViewport?.height动态更新 CSS 变量,再用该变量控制容器高度
fixed 定位输入框在 iOS 上失去焦点或跳动
iOS 的软键盘行为特殊:它会把 position: fixed 元素“拖”到键盘上方,但若父容器有 transform、perspective 或 will-change,会导致定位失效甚至输入框瞬间消失。
实操建议:
- 避免对
input父级或 body 添加transform(比如某些“滚动穿透” hack 会加transform: translateZ(0)) - 把输入框放在
body直接子元素中,减少嵌套层级 - 用
position: absolute替代fixed,配合bottom: 0和父容器position: relative,更可控
如何让输入框始终可见——不靠 JS 滚动而是靠 CSS 自适应
手动调用 scrollIntoView 在某些安卓机型上会触发双次滚动或卡顿;而纯 CSS 方案更轻量、更稳定。
实操建议:
- 给输入框外层容器设
scroll-margin-bottom: 60px(预留键盘高度空间) - 确保该容器可滚动(如
overflow-y: auto,且内容足够高) - 聚焦时浏览器自动将
input滚到可视区,且留出底部边距——无需监听事件 - 注意:这个特性依赖
scroll-behavior: smooth是否启用,以及是否在文档流中(不能是display: none或visibility: hidden)
安卓 WebView 中 visualViewport 不可用怎么办
部分低版本安卓 WebView(如 Android 9 内置 WebView)不支持 visualViewport API,window.innerHeight 在键盘弹出后也不准确,导致 JS 计算高度失败。
实操建议:
- 优先检测
'visualViewport' in window,再 fallback 到screen.height - screen.availHeight(粗略估算键盘高度) - 不要依赖
resize事件——安卓上它可能不触发,或延迟严重;改用focusin/blur配合setTimeout延迟读取innerHeight - 最稳方案:放弃动态适配,用相对单位(如
rem)+ 底部留白(padding-bottom: 80px),靠用户手动滚动
真正难的不是写几行 CSS,而是判断当前环境到底该信 vh、dvh、visualViewport 还是干脆放弃自适应——不同机型、系统版本、WebView 内核的行为差异太大,得逐层降级,而不是寄希望于一个“通用解”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











