软键盘遮挡问题根因是viewport配置错误:必须设height=device-height且禁用user-scalable=no,否则iOS Safari不触发visualViewport重绘,JS无法感知键盘弹出;focus中调scrollIntoView({block:'nearest',inline:'nearest'})最可靠。

viewport meta 标签写错,软键盘问题根本没法靠 JS 修复——它不是滚动没写对,而是浏览器压根不给你感知键盘的机会。
为什么 user-scalable=no 在 iOS 上是静默破坏
iOS Safari 遇到 user-scalable=no 会直接忽略软键盘弹出时的 visualViewport 重绘。结果就是:visualViewport.height 始终等于屏幕物理高度,window.innerHeight 也不变,JS 完全无法判断键盘是否弹起。
-
user-scalable=no不报错、不警告,但所有基于视口变化的逻辑(比如滚动、定位、高度计算)全部失效 - 哪怕你写了
visualViewport.addEventListener('resize', ...),事件也永远不会触发 - 微信 X5 内核更狠:不仅无视
visualViewport,连focus事件都可能延迟或丢失
height=device-height 不是可选,而是 iOS 的硬性开关
没有 height=device-height,iOS Safari 就不会在键盘弹出时更新 visualViewport 和 window.innerHeight,导致你写的 scrollIntoView 或高度监听全部失准。
- Android Chrome 对
height=device-height支持弱,但至少不阻断事件;iOS 没它就彻底“失明” - 别用
height=100%或height=812px替代——这些是静态值,无法响应键盘动态变化 - 必须和
width=device-width同时存在,否则部分旧版 WebView 会回退到桌面渲染模式
focus 事件里调 scrollIntoView 为什么比 resize 更可靠
因为 iOS Safari 在键盘真正弹出前就触发了 focus,此时调 scrollIntoView({ block: 'nearest', inline: 'nearest' }) 才能抢在遮挡发生前完成滚动;而 resize 触发太晚,且 Android 和 iOS 触发时机不一致。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
立即学习“前端免费学习笔记(深入)”;
- 别等
focusin或input事件——它们比focus还晚,光标可能已被盖住 - 不要在
click里提前调scrollIntoView,部分 Android 浏览器会在 focus 前执行,滚动目标还没聚焦,无效 -
{ block: 'nearest', inline: 'nearest' }是关键:它只做最小必要滚动,避免把光标顶出可视区域顶部
blur 时不处理,页面就永远悬在半空
focus 时滚上去了,blur 时不恢复,用户再点其他输入框,页面可能卡在错误位置,甚至光标消失——这不是 bug,是漏掉了状态闭环。
- 记录
lastScrollTop必须在focus触发前一刻取:const lastScrollTop = window.visualViewport?.pageTop || window.scrollY,别用document.body.scrollTop(iOS 上常为 0) - blur 后加 200ms 防抖再执行
window.scrollTo(0, lastScrollTop),避免和系统收起动画冲突 - 别用
window.scrollTo(0, 0)硬滚回顶,会打断用户浏览上下文,尤其长表单场景下体验极差
最麻烦的不是写多少 JS,而是 viewport 标签一旦写错,所有后续逻辑都在假数据上运行——它藏得深、不报错、只在真机上暴露,且不同机型表现还不一样。


















