软键盘弹出时 fixed 元素被顶起是浏览器对 visualViewport 的真实响应,需从 viewport 配置、focus 时机、scrollIntoView 和 resize 恢复三方面协同解决:viewport 必含 height=device-height 且 user-scalable=yes;focus 时调用 scrollIntoView({block:'nearest',inline:'nearest'});resize 时恢复 scrollY。

软键盘弹出时 position: fixed 底部元素被顶起,不是 bug,而是浏览器对 visualViewport 的真实响应——iOS 和 Android 都会压缩可视区域高度,fixed 元素自然跟着“上浮”。靠单纯改 CSS 或监听 resize 很难稳住,关键得从 viewport 配置 + 事件时机 + 滚动锚点三处同时干预。
viewport meta 必须包含 height=device-height 且禁用 user-scalable=no
漏掉 height=device-height,iOS 上 window.innerHeight 在键盘弹出前后完全不变,所有基于高度判断的 JS 逻辑(比如 scroll、show/hide)直接失效。而 user-scalable=no 不是防缩放工具,它是静默禁用键盘视口重绘的开关:一旦存在,visualViewport.height 永远等于屏幕物理高度,resize 事件不触发,fixed 元素彻底失联。
推荐写法:
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes, height=device-height">
-
width=device-width和initial-scale=1.0必须共存,缺一不可;单独写前者,iOS 可能回退到 0.5x 缩放模式 -
user-scalable=yes或直接省略(默认就是 yes),用maximum-scale=1.0, minimum-scale=1.0实现视觉不可缩放 - 真机测试必须做:DevTools 模拟器不触发真实的视口挤压,Safari 真机点 input 后看地址栏是否收起、状态栏是否下移
input focus 事件中调用 scrollIntoView({ block: 'nearest', inline: 'nearest' })</H3>
<p>这是当前最轻量、最稳的滚动修复手段。别在 <code>click 或 blur 里调,时机全错:iOS 在键盘弹出前就触发 focus,此时滚动最准;Android 部分机型虽稍晚,但 nearest 模式只做最小位移,不会把光标滚出视口顶部。
立即学习“前端免费学习笔记(深入)”;
示例写法:
input.addEventListener('focus', () => {<br> input.scrollIntoView({ block: 'nearest', inline: 'nearest' });<br>});
- 必须监听
input或textarea自身的focus,不是window的focusin - 绝对不要加
behavior: 'smooth'——老版微信 X5 内核不支持,会静默失败 - 参数必须是
{ block: 'nearest', inline: 'nearest' };start会强行滚到顶部,遮挡更严重
软键盘收起后页面悬空?监听 resize 并手动恢复 scrollY
键盘收起时,iOS 和 Android 都会触发一次 resize(高度变大),这是唯一可靠的信号。仅靠 blur 不行——它在键盘开始收起时就触发,此时视口还没恢复,滚动位置已错乱。
需配合保存和还原逻辑:
let lastKnownHeight = window.innerHeight;<br>let savedScrollTop = 0;<br><br>window.addEventListener('resize', () => {<br> if (window.innerHeight > lastKnownHeight) {<br> window.scrollTo(0, savedScrollTop);<br> }<br> lastKnownHeight = window.innerHeight;<br>});<br><br>// 记录初始 scrollY<br>savedScrollTop = window.scrollY;
- 别依赖
scrollRestoration: 'auto',它在多数 WebView 中不可靠 - 如果页面本身有滚动容器(如
overflow: auto的 div),要同步保存/恢复该容器的scrollTop,而非window - 这个逻辑必须在
mounted或 DOM ready 后立即注册,不能延迟
真正容易被忽略的是:viewport 配置错误会让所有 JS 修复失效,而 focus 时机错配会让滚动变成“看起来动了,其实没对准”。这两点不先搞定,后面加再多层 CSS hack 或 resize 监听都只是临时补丁。



















