iOS Safari 中需在 input/textarea 的 focus 事件中调用 scrollIntoView({block:'nearest',inline:'nearest'}),配合正确 viewport 设置(含 height=device-height 且 user-scalable=yes)及 blur 时还原滚动位置,才能可靠适配软键盘弹出。

focus 事件里调 scrollIntoView 才有效
软键盘弹出前,iOS Safari 就已触发 focus,此时滚动最准;Android 部分机型在 click 后还没真正获得焦点,等 resize 或 click 再滚动就晚了。写在 window.addEventListener('focusin', ...) 也无效——它捕获的是整个窗口焦点,不是输入框自身。
必须直接监听 input 或 textarea 元素的 focus 事件:
input.addEventListener('focus', () => {
input.scrollIntoView({ block: 'nearest', inline: 'nearest' });
});
- 别用
behavior: 'smooth':微信 X5 内核会静默失败,光标不动也不报错 - 参数必须是
{ block: 'nearest', inline: 'nearest' }:只做最小滚动,避免把光标顶到视口顶部以外 - 多个输入框要分别绑定,不能只绑父容器——事件委托在这里不生效
viewport meta 标签写错,JS 就白写
90% 的“滚动没反应”问题,根源是 <meta name="viewport"> 锁死了浏览器对键盘弹出的响应能力。iOS 会因此忽略 visualViewport.height 变化,JS 根本感知不到键盘已起。
关键两点必须同时满足:
立即学习“前端免费学习笔记(深入)”;
- 必须包含
height=device-height:否则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 收起键盘后页面不自动回滚,留白+错位是常态。
- 记录滚动位置不能依赖
document.body.scrollTop(iOS 常为 0),要用window.scrollY或visualViewport?.pageTop - 监听
blur事件,配合 200ms 防抖,再执行一次位置还原 - 还原目标不是“滚回顶部”,而是恢复到 blur 前的视口垂直偏移量
inputmode 和 type 搭配错了,键盘根本不会变
inputmode 是软提示,不是强制指令。它不起作用,90% 是因为 type 没配对。
-
inputmode="tel"必须配type="tel",别用type="text"+inputmode="tel"——语义弱、自动填充可能失效 - 金额或验证码别用
type="number":iOS 会把小数点转成逗号、禁用粘贴、干扰布局;改用type="text" inputmode="decimal"更可控 -
inputmode="email"对中文输入法无效——用户切到拼音后,@ 键就消失了,这是系统级限制,前端拦不住 -
inputmode="search"和inputmode="url"基本别依赖:国产安卓浏览器(如微信 X5)大多忽略,纯属视觉提示
真机验证比文档更重要:同一段代码,在 iPhone 和 vivo 系统键盘上的表现可能完全不同。



















