resize事件不可靠,应改用focusin/blur组合监听焦点并结合visualviewport.resize降级处理,动态调整fixed元素需用absolute定位+延迟读取坐标。

resize 事件在虚拟键盘弹出时基本不可靠,不建议作为主要检测手段。iOS Safari(尤其是 15.4+)根本不会触发它,Android 行为也不统一——这不是 bug,是浏览器对「软键盘作为覆盖层、不改变 layout viewport」的设计选择。
为什么监听 resize 解决不了遮挡问题
- 软键盘弹出时,
window.innerHeight可能不变、突变、或延迟变化,resize不保证触发,更不保证时机准确 - 即使触发,也常只在键盘收起时发生一次,完全漏掉弹出瞬间,输入框早已被顶出可视区
-
visualViewport.height虽会变,但它在 Android 上支持差、iOS 上有抖动,直接用它算“键盘高度”误差大
真正该监听的事件组合
- 优先用
focusin(不是focus,冒泡更可靠)捕获任意input或textarea聚焦 - 兜底监听
blur恢复状态,避免失焦后定位残留 - 若需感知真实视口变化,用
visualViewport.addEventListener('resize', ...),但必须带降级逻辑
动态调整 fixed 元素的实操要点
- 不要改
bottom: 0或height:它们无法响应键盘动态高度,且易导致布局错乱 - 推荐方案是临时切换定位方式:
- 聚焦时,将底部按钮设为
position: absolute,并用getBoundingClientRect().bottom计算其距视口底边距离,再设bottom: ${window.innerHeight - rect.bottom}px - 必须加
setTimeout(() => {}, 0)或requestAnimationFrame延迟读取,否则getBoundingClientRect()返回旧坐标 - 失焦后立刻恢复
position: fixed; bottom: 0,否则滚动时定位彻底失效
- 聚焦时,将底部按钮设为
最容易被忽略的细节
- 所有计算前先确认
document.activeElement === inputEl,防止异步焦点转移导致状态错位 - 若页面用了
transform、overflow: hidden或fixed父容器,getBoundingClientRect()和scrollIntoView()都可能失效,且无报错提示 -
env(keyboard-inset-bottom)在 iOS 16.4+ 是最优解,但安卓完全不支持,不能当作唯一方案
别在 resize 上浪费调试时间——它不是入口,只是个失效的幻觉。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











