移动端 input 聚焦时被虚拟键盘遮挡的解决方案是调用 scrollintoview({block: ‘nearest’, inline: ‘nearest’}),需在 focus 事件中执行;viewport 须设 height=device-height 且禁用 user-scalable=no;键盘收起后通过 resize 事件 + 防抖 scrollto 恢复位置。

input 聚焦时底部被虚拟键盘盖住
这是移动端最常遇到的布局错位问题:用户点击 <input>,键盘弹出,但输入框位置没变,直接被盖在键盘下面。根本原因不是 CSS 没写好,而是浏览器对viewport 高度的处理逻辑变了——键盘弹起时,部分 Android 和 iOS 会缩放或重算可视区域,而 position: fixed 或bottom: 0元素不会自动上移。
- 别依赖
window.innerHeight做滚动定位,它在键盘弹出后可能还没更新(尤其 iOS Safari) - 监听
focus事件后立刻scrollIntoView({behavior: 'smooth'})比手动计算更可靠 - 对
type="text"、type="tel"等软键盘触发型输入框才需处理;type="hidden"或disabled状态不用管 - iOS 16.4+ 对
visualViewport支持变好,可用visualViewport.addEventListener('resize', ……)捕获键盘高度变化,但 Android WebView 大多不支持
使用 scrollIntoView 强制滚动到输入框顶部
比起自己算 top、offset、scrollTop,scrollIntoView是目前兼容性最好、代码最轻量的解法。它不依赖页面是否启用 overflow: hidden 或是否嵌套在 position: relative 容器里。
- 必须在
input的focus事件回调里调用,不能放在click或touchstart里(时机太早,DOM 还没获得焦点) - 加
{block: 'nearest', inline: 'nearest'}参数避免过度滚动;默认block: 'start'会把输入框顶到视口最上方,反而遮住光标 - 某些老版微信内置浏览器(X5 内核)不支持
behavior: 'smooth',直接去掉该参数更稳妥 - 示例:
input.addEventListener('focus', () => {input.scrollIntoView({ block: 'nearest', inline: 'nearest'}); });
viewport meta 标签写法影响键盘行为
<meta name="viewport">不是摆设。写错一个参数,iOS 会禁用缩放但同时锁死 visualViewport 高度,导致所有滚动逻辑失效。
- 必须包含
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事件不靠谱——用户切到其他 App 再切回来,blur根本不会触发 - 更稳的办法是监听
resize事件,配合setTimeout防抖:当window.innerHeight明显变大(比如 +200px),就window.scrollTo(0, 0)或还原之前存的scrollY - 别用
document.body.scrollTop = 0,Safari 可能无视;统一用window.scrollTo(0, 0) - 如果页面本身有锚点跳转或路由滚动行为,记得在
scrollTo前加history.scrollRestoration = 'manual',防止浏览器覆盖你的修复
事情说清了就结束。真正难的不是写几行 JS,而是得记住:iOS 和 Android 对同一个 viewport 参数反应不同,同一个 focus 事件在不同 WebView 里触发时机差 200ms,而用户不会等你 debug。






























