Flex布局下input被顶起主因是键盘弹出压缩visualViewport.height,导致min-height:100dvh容器被动缩放,而flex:1内容区未重算滚动锚点;iOS Safari收起键盘后常残留缩放状态,需setTimeout 300ms scrollTo(0,0)修复。

为什么 flex 布局下 input 获取焦点仍会被顶起
不是 flex 写错了,而是键盘弹出时浏览器压缩 visualViewport.height,而页面容器若用了 min-height: 100vh 或 100dvh,其高度会随视口缩放被动变化——但内部 flex: 1 的内容区不会自动重算滚动锚点,导致输入框被“推”到可视区外。更隐蔽的是:iOS Safari 在键盘收起后常残留 visualViewport.height 缩小状态,造成后续滚动错位。
用 min-height: 100dvh + flex: 1 必须配 overflow-y: auto
只设 display: flex; flex-direction: column; min-height: 100dvh 不够,关键在内容区必须显式接管滚动:
-
.main必须是直接子元素,且设flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch - 不能把
overflow-y: auto放在.page容器上——那会导致整个页面滚动,输入框仍可能被顶出可视区 - 避免给
.main设固定height,它必须靠flex: 1动态撑开,否则键盘弹出时无法自适应收缩 - 如果内容不足一屏,
.main高度为 0,此时需加min-height: 0防止 flex 项目塌陷(Safari 旧版常见)
position: sticky 替代 fixed 底部栏的实操要点
底部操作栏(如输入框旁的发送按钮)别用 position: fixed,改用 position: sticky; bottom: 0,但有硬性前提:
- 父容器必须设
min-height: 100vh(100dvh在 iOS 16.4+ 更准,但降级需 fallback) - 父容器不能有
transform、filter或will-change,否则 sticky 失效 - 底部栏必须是
.main的同级兄弟节点,不能嵌套在.main内部——否则它会随内容滚动而消失 - 在安卓低版本 WebView 中,sticky 可能不触发,此时需用
@supports not (position: sticky)降级为position: absolute+ JS 监听
键盘收起后页面卡在错误滚动位置怎么办
这是最易被忽略的残余问题:iOS 键盘收起动画结束前,visualViewport.height 尚未恢复,window.innerHeight 仍是压缩值,导致 scrollTo 或 focus() 后定位偏移。解决方式很具体:
立即学习“前端免费学习笔记(深入)”;
- 监听
blur事件后,用setTimeout(() => { window.scrollTo(0, 0); }, 300)—— 300ms 是 iOS 键盘收起动画典型时长 - 不要依赖
resize事件判断键盘状态,它在部分安卓机上会误触发多次 - 若页面有锚点跳转逻辑(如 hashchange),需在
blur后手动调用history.replaceState清除临时 hash,防止返回时复现错位 - 对
input元素,可加scrollIntoView({ behavior: 'smooth', block: 'nearest' })替代默认行为,减少强制滚动抖动


















