软键盘遮挡问题的根源是 viewport 行为与事件时机不匹配,最稳解法是在 input/textarea 的 focus 事件中调用 scrollIntoView({ block: 'nearest', inline: 'nearest' }),并确保 viewport meta 包含 height=device-height 且禁用 user-scalable=no。

直接结论:软键盘遮挡不是样式问题,而是 viewport 行为 + 事件时机没对齐——focus 里调 scrollIntoView({ block: 'nearest', inline: 'nearest' }) 是当前最稳、最轻量的解法。
focus 事件里调 scrollIntoView 才有效
很多代码写在 click 或 resize 里,但时机全错了。iOS Safari 在键盘弹出前就触发 focus,此时调 scrollIntoView 反而最准;Android 部分机型在 click 后还没获得焦点,滚动就失效了。
- 必须监听
input或textarea元素自身的focus事件,不是window的focusin - 别加
behavior: 'smooth'—— 老版微信 X5 内核不支持,会静默失败 - 参数用
{ block: 'nearest', inline: 'nearest' }:只做最小必要滚动,避免光标被顶出视口顶部 - 示例:
input.addEventListener('focus', () => {<br> input.scrollIntoView({ block: 'nearest', inline: 'nearest' });<br>});
viewport meta 标签写错,JS 就白写
90% 的“滚动无效”问题,根源是 <meta name="viewport"> 锁死了浏览器对键盘弹出的响应能力。iOS 会因此忽略 visualViewport.height 变化,JS 根本感知不到键盘已起。
- 必须包含
height=device-height:否则 iOS Safari 的window.innerHeight在键盘弹出后不变,无法判断遮挡 - 绝对禁用
user-scalable=no:它会让 iOS 静默禁用 viewport 重绘,visualViewport.height永远等于屏幕高度 - 推荐写法:
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=yes, height=device-height">
- Android Chrome 对
height=device-height支持弱,但至少不会破坏逻辑;user-scalable=no在 iOS 上才是真·静默杀手
blur 时不处理,页面就悬在半空
focus 时滚上去了,blur 时不恢复,用户再点别的输入框,光标可能直接消失——尤其 iOS 收起键盘后页面不自动回滚,留白+错位是常态。
立即学习“前端免费学习笔记(深入)”;
- 监听
blur事件,配合 200ms 防抖,再执行一次位置还原 - 记录滚动位置不能依赖
document.body.scrollTop(iOS 常为 0),要用:const lastScrollTop = window.visualViewport?.pageTop || window.pageYOffset;
- 还原时别用
window.scrollTo(0, 0),会打断用户浏览上下文;应恢复到lastScrollTop - fixed 底部按钮场景更复杂:需临时改
position: absolute或动态计算 bottom 值,单纯 scroll 不够
别碰 100vh 和 fixed 布局的组合
这是移动端软键盘布局崩塌的高发区。iOS 键盘覆盖式弹出,100vh 不变,但 fixed 元素却卡在原位置;安卓压缩式弹出,100vh 缩小,fixed 元素又被挤变形。
- 禁止给
html或body设height: 100%或min-height: 100vh - 底部按钮不用
position: fixed,改用position: sticky+ 容器高度自适应 - 表单区域避免嵌套多层
overflow: hidden容器,会拦截scrollIntoView的冒泡行为 - 如果必须用
fixed,得在focus时监听visualViewport高度变化(iOS 16.4+ 支持),并动态调整bottom值
真正难的不是写几行 JS,而是把 viewport、事件时机、滚动定位、平台差异这四层逻辑拧成一股绳——漏掉任意一层,都可能在某台 iPhone 或某个微信版本里突然失效。



















