根本原因是fixed锚定视觉视口,键盘弹出会压缩该视口但定位值不重算;需用env(keyboard-inset-bottom)(ios 16.4+)、100dvh、focusin/blur动态切absolute或flex布局四者组合兜底,并确保viewport-fit=cover生效。

直接用 position: fixed 做底部操作栏,在软键盘弹出后被顶起或遮挡,不是你 CSS 写错了,而是浏览器把 fixed 锚定在「视觉视口(visual viewport)」上,而键盘一弹,这个视口就塌了——但定位值不会自动重算。纯靠 z-index 或调 bottom 数值解决不了根本问题。
用 env(keyboard-inset-bottom) 原生避让(iOS 16.4+)
iOS Safari 16.4 起支持该环境变量,键盘弹出时它会自动返回当前键盘高度(单位 px),无需 JS 干预:
-
bottom: env(keyboard-inset-bottom, 0px)必须搭配<meta name="viewport" content="viewport-fit=cover">,否则变量恒为0px - 必须用
@supports (bottom: env(keyboard-inset-bottom))包裹,否则旧版 Safari 可能跳过整条规则甚至解析失败 - 不能和
svh混用,例如bottom: calc(0px + 100svh)是错的——svh是高度单位,env(keyboard-inset-bottom)是偏移量 - 安卓完全不支持,所以这条规则只能作为 iOS 的增强,不能当唯一解
用 100dvh 替换 100vh 控制容器高度
100vh 固定等于设备物理屏幕高度,键盘弹出后仍不变;100dvh(dynamic viewport height)会随软键盘动态更新,是现代浏览器首选:
- 根容器(如
body或#app)设height: 100dvh,而非height: 100vh - 同样需加
<meta name="viewport" content="viewport-fit=cover">才能触发更新 - 用
@supports (height: 100dvh)做渐进增强,老版本回退到100vh+ JS 补位 - 注意:部分安卓 WebView(如华为 EMUI)对
dvh支持不稳定,不能只依赖它
监听 focusin + setTimeout 动态切 position: absolute
这是兼容性最广、可控性最强的 JS 方案,适用于所有平台,尤其安卓 WebView 和老 iOS:
- 监听
focusin(不是focus,冒泡更可靠)到<input>或<textarea></textarea> - 在回调里用
setTimeout(() => { }, 0)确保 DOM 重排完成后再读window.innerHeight和input.getBoundingClientRect().bottom - 计算偏移:
bottom: window.innerHeight - inputRect.bottom,然后设position: absolute+ 该bottom值 -
blur后立刻恢复position: fixed; bottom: 0,并调用el.style.removeProperty('top')和el.style.removeProperty('bottom')清除内联样式 - 关键检查点:所有计算前先确认
document.activeElement === inputEl,防止异步焦点转移导致状态错乱
用 flex 布局把“固定”效果做进文档流
彻底绕开视口锚定问题,靠父容器布局推导位置,不依赖 fixed 或 absolute:
- 根容器设
display: flex; flex-direction: column; min-height: 100dvh(或100vh+ fallback) - 内容区设
flex: 1; overflow-y: auto; -webkit-overflow-scrolling: touch - 底部元素作为兄弟节点,不设
position,仅靠margin-top: auto或align-self: flex-end推到底部 - 避免把底部栏放进内容区内部再设
align-self——那只是视觉贴底,仍可能被键盘顶起 - 若页面有 transform、
overflow: hidden或fixed父容器,getBoundingClientRect()可能返回错误坐标且无报错提示
最容易被忽略的是:所有方案都得处理 document.activeElement 的实时一致性,以及 viewport-fit=cover 这个 meta 标签是否生效——它不光影响安全区,还决定 env(keyboard-inset-bottom) 和 100dvh 能否被识别。没有它,很多 CSS 原生能力直接失效。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











