ios键盘弹出时focusin监听不到高度变化,需组合focusin+延迟检测+视口比对;vh失效因系统覆盖视口定义,应优先用100dvh并降级;多层嵌套表单失焦回滚需定位真实滚动容器;iframe中layer弹窗须用top.layer并同步顶层scrolly。

focusin 事件监听不到 iOS 键盘弹出?别硬等 resize
iOS Safari 不会触发 resize,focusin 虽能捕获焦点,但此时键盘尚未完全展开,window.innerHeight 还没变化,直接读取会误判。真正可靠的是组合监听:focusin + 延迟检测 + 视口高度比对。
- 在
focusin后用setTimeout延迟 100–200ms 再读window.innerHeight,避开 Safari 的渲染延迟 - 记录初始
document.documentElement.clientHeight,对比弹出后是否显著缩小(安卓)或几乎不变(iOS) - 避免只依赖
screen.height或visualViewport.height——后者在旧版 iOS Safari 中不可用,且部分 WebView 未启用 - 不要在
focusin里立刻调scrollIntoView:iOS 下可能触发两次滚动,造成跳动
vh 单位在键盘弹出时失效的根本原因
100vh 在软键盘弹出时“失真”,不是 CSS bug,而是浏览器视口定义被系统覆盖。iOS 下 vh 始终基于设备物理高度,不随键盘状态缩放;安卓则多数按压缩后视口计算——导致同一份 CSS 在双端表现分裂。
- 禁用
html, body { height: 100%; }+.page { height: 100vh; }组合:它会让 iOS 页面失去滚动能力,输入框一聚焦就卡死 - 改用
min-height: 100dvh(dynamic viewport height):现代 Safari/Chrome 支持,能响应键盘状态变化,但需加@supports (height: 100dvh)降级 - 对老版本 iOS,回退到 JS 动态设
style.height = window.innerHeight + 'px',并在focusout后重置 - 绝对定位元素(如底部 fixed 按钮)慎用
bottom: 0:键盘弹出后应改用bottom: calc(env(keyboard-inset-bottom, 0px)),但仅限 iOS 16.4+ 支持
多重表单嵌套下 input 失焦后页面不回滚?别只靠 scrollTo
当页面有多个 form、多层 div 包裹、或存在自定义滚动容器(如 overflow-y: auto 的父级),iOS 收起键盘后 document.body.scrollTop 和 document.documentElement.scrollTop 可能都为 0,但实际滚动位置在子容器内——直接 window.scrollTo(0, 0) 无效。
- 优先检测并操作真实滚动容器:
const scrollEl = document.querySelector('.scroll-container') || document.documentElement - 在
focusout后用getBoundingClientRect()判断输入框是否还在视口内,若已偏移,则scrollEl.scrollTop -= 20微调,比硬跳更自然 - 避免用
setTimeout硬等 200ms 后scrollTo:某些机型键盘收起延迟达 300ms+,应监听blur后连续轮询visualViewport?.height变化直至稳定 - 若使用了
position: fixed的弹窗表单,确保其父级没有transform:否则 fixed 定位参照系错乱,滚动修复会完全失效
layer.open 弹窗内表单被键盘遮挡?关键在 top.layer 而非 this.layer
在多层 iframe 场景下(如微信 H5 嵌在公众号网页中),layer.open() 默认读取当前 iframe 的 window.innerHeight 和 scrollTop,但键盘弹出影响的是顶层窗口,导致弹窗 offset 计算严重偏差——底部按钮永远被盖住。
- 必须显式使用
top.layer.open()替代layer.open(),强制所有计算基于顶层上下文 - 在弹窗打开前,手动同步顶层滚动偏移:
top.scrollY赋值给弹窗内部的定位逻辑,否则即使用了top.layer,初始位置仍可能错 - 禁用弹窗内的
type="text"输入框自动聚焦(autofocus):iframe 嵌套下 autofocus 行为不可靠,极易触发错误滚动 - 若无法控制 iframe 结构,改用原生
<dialog></dialog>:它天然跨 iframe 边界渲染遮罩与内容,且showModal()自动处理键盘避让逻辑
最易被忽略的一点:键盘弹出时,visualViewport 的 height 和 scale 变化是异步的,且不同机型节奏不一致。任何依赖“一次判断就永久生效”的方案,都会在 iPhone 15 Pro 或 iPad mini 上突然失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











