应改用min-height: 100dvh; max-height: 100dvh; overflow-y: auto替代100vh,因其能动态响应键盘弹出;必须配viewport meta标签并用@supports包裹,辅以visualviewport监听或focusin降级,同时对flex子项设flex-shrink: 0防压缩。

别用 100vh 做全屏高度容器
它在键盘弹出时会“卡死”在初始值,iOS Safari 和多数安卓 WebView 不更新 window.innerHeight,但可视区域已明显变小,结果就是页面撑满、输入框被截断。实际测试中,100vh 容器在 iPhone 上可能从 667px 骤降到 400px 以下,而样式毫无反应。
改用 min-height: 100dvh; max-height: 100dvh; overflow-y: auto —— 100dvh 是动态视口单位,代表“无键盘状态下的完整高度”,Safari 16.4+ 和 Chrome 105+ 已稳定支持。必须配 <meta name="viewport" content="width=device-width, initial-scale=1.0">,否则 dvh 会退化失效。
老版本兼容方案:
- 用
min-height: 100vh作为 fallback - 监听
focusin给根容器加class="keyboard-open",层叠设置height: auto或min-height: fit-content - 避免同时写
height: 100vh和min-height: 100dvh,CSS 会优先应用前者导致降级失败
visualViewport 是唯一可靠的键盘高度检测方式
resize 事件在 iOS 上基本不触发键盘弹出,window.innerHeight 更新延迟且抖动大,只有 visualViewport.height 能实时反映用户真正看到的可视区域高度。
实操要点:
- 页面加载即缓存基准值:
const baseHeight = visualViewport.height - 监听
visualViewport.addEventListener('resize', handler),不是window的resize - 计算键盘高度:
const kbHeight = baseHeight - visualViewport.height,差值 > 150px 可判定为键盘弹出 - 不支持
visualViewport的环境(如 iOS 15.3、部分安卓 WebView)必须降级到focusin+setTimeout(() => { ... }, 0)读取getBoundingClientRect().bottom
底部 fixed 按钮被顶起?优先换 position: sticky
position: fixed 锚定的是视觉视口(visualViewport),键盘一出,这个“锚点”就塌了。iOS 会把按钮钉在物理屏幕底边,Android 则行为碎片化,纯靠 z-index 或 bottom: 0 无效。
更稳的选择:
- 用
position: sticky; bottom: 0:不脱离文档流,随滚动自然响应,iOS 15.4+/Chrome 90+ 支持良好 - iOS 16.4+ 可用
bottom: env(keyboard-inset-bottom, 0px),但必须@supports (bottom: env(keyboard-inset-bottom))包裹,安卓完全不支持,不能当主力方案 - 安卓 fallback:给最外层容器加
padding-bottom: 60px(按按钮真实高度设),而非操作body的margin-bottom(易触发外边距合并)
flex 布局里内容被压缩?关掉 flex-shrink
用 display: flex; flex-direction: column 做页脚吸底时,键盘弹出会挤压中间区域,文字缩成一条线——根本原因是 flex 子项默认 flex-shrink: 1,被强制压缩。
关键修复:
- 给需要保持高度的子项(如输入框容器、内容区)显式设置
flex-shrink: 0 - 避免对父容器设
height: 100vh,改用min-height: 100dvh+overflow-y: auto - 慎用
transform(如translateZ(0)):它会触发 iOS 合成层,加剧定位偏移 - 如果必须用
position: fixed输入框,别直接调scrollIntoView()—— 它在 fixed 元素上常只滚到键盘边缘;改用scroll-margin-bottom: 120px或手动算偏移:window.scrollTo(0, inputEl.getBoundingClientRect().top - 100)
真实项目里最容易被忽略的点是:没有统一绑定所有动态插入的 <input> 和 <textarea></textarea>,漏掉一个就可能让整个适配逻辑失效;另外,visualViewport 的监听必须在页面加载完成前注册,晚于 DOM ready 就可能错过第一次键盘弹出。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











