根本原因是100vh在键盘弹出时不更新,导致flex容器虚高而底部元素被挤出可视区;应改用100dvh(chrome 105+/safari 16.4+支持),并配合height锁定、padding-bottom: calc(48px + env(safe-area-inset-bottom))及box-sizing: border-box确保稳定。

flex布局底部吸底为什么还会被顶起
根本原因不是flex写错了,而是你用的视口单位(比如100vh)在软键盘弹出时没更新。iOS Safari 和多数安卓 WebView 中,window.innerHeight会缩小,但 CSS 里的vh值仍按初始高度计算,导致 flex 容器撑得过高,底部元素被“挤”到可视区外——看起来像被顶起,其实是容器虚高了。
用100dvh替代100vh能解决大部分情况
100dvh是动态视口单位,软键盘弹出时会自动重算,比100vh更可靠。但它有兼容性边界:
- Chrome 105+、Safari 16.4+、Edge 105+ 支持;旧版 iOS Safari(
- 不能直接替换所有
100vh——如果页面本身有地址栏收放行为,100dvh可能比实际可视区还小,需 fallback - 必须搭配
min-height而非height,防止内容不足时底部上浮
推荐写法:.page { min-height: 100dvh; min-height: 100vh; },后者作为降级。
安卓 WebView 中env(safe-area-inset-bottom)不更新怎么办
微信、QQ、企业微信等内置 WebView 常不响应env(safe-area-inset-bottom)变化,此时 flex 吸底失效的本质是容器高度没收缩。JS 是唯一兜底手段:
- 只监听
input和textarea的focusin事件(避免focus冒泡干扰) - 记录
window.innerHeight初始值,聚焦后对比:差值 > 150px 就视为键盘弹出 - 动态给根容器加
style.height = window.innerHeight + 'px',让 flex 重新计算剩余空间 - 别用
resize事件——它在很多安卓机型上不触发或延迟严重
底部按钮固定高是前提,否则padding-bottom方案会失效
如果你用padding-bottom: calc(60px + env(safe-area-inset-bottom))给内容区留空,那60px必须和按钮真实高度完全一致。常见陷阱:
- 按钮用了
line-height或flex居中,但height没显式设值,导致 JS 获取getBoundingClientRect().height和 CSS 中预设值不匹配 - 按钮文字换行后高度变大,但
padding-bottom仍是静态值,最后一项必然被遮 - 横竖屏切换时,
env(safe-area-inset-bottom)在横屏下为0,但你的calc()里没做条件判断
真正稳定的做法:按钮高度锁定(height: 48px),配合box-sizing: border-box,再用padding-bottom留空——其他路径都容易在某个机型或 UA 下崩。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











