env(keyboard-inset-bottom) 单独使用无效,仅 ios safari 16.4+ 原生支持,安卓及旧版 safari 不识别,需配合 @supports 和 fallback(如 env(keyboard-inset-bottom, 0px)),并结合 focusin/blur 监听与延迟读取坐标等 js 逻辑才能可靠适配键盘。

直接用 env(keyboard-inset-bottom) 是最简方案,但必须搭配 JS 监听和降级逻辑,否则在安卓或旧 Safari 上必失效。
为什么 env(keyboard-inset-bottom) 单独写没用
它只在 iOS Safari 16.4+ 原生支持,安卓 WebView、Chrome for Android、旧版 Safari(如 15.3)完全不识别。如果只写 bottom: env(keyboard-inset-bottom),浏览器会忽略整条规则,回退到 bottom: 0——而键盘弹出后这个值就错位了。
必须写成带 fallback 的形式:bottom: env(keyboard-inset-bottom, 0px),且用 @supports 包裹:
button.fixed-bottom {
position: fixed;
bottom: 0;
}
@supports (bottom: env(keyboard-inset-bottom)) {
button.fixed-bottom {
bottom: env(keyboard-inset-bottom, 0px);
}
}
- 漏掉
@supports,老浏览器会把整段 CSS 当作无效,连 fallback 都不生效 - 漏掉
, 0px,键盘收起后按钮悬空(因为env()返回空值,不是0px) - 不能只靠它响应键盘弹出——它不触发重排,也不通知 JS 状态变化
必须监听 focusin 和 blur,别碰 resize
resize 在 iOS Safari(尤其 15.4+)中触发率低于 20%,安卓延迟严重,且常只在键盘收起时触发一次,完全错过弹出瞬间。真正可靠的入口是用户点进输入框的那一刻。
- 监听所有可聚焦元素:
input、textarea、[contenteditable] - 在
focusin回调里立刻检查document.activeElement,防止异步焦点转移导致误判 - 用
setTimeout(() => { /* 读坐标 */ }, 0)延迟取值,否则getBoundingClientRect()还是键盘弹出前的旧值 -
blur后必须立刻清除内联样式:el.style.removeProperty('top')和el.style.removeProperty('bottom'),再恢复position: fixed
用 position: absolute 替代时的三个硬条件
只改 position 值不会解决问题,absolute 锚定的是最近的 position: relative 祖先。如果这个祖先高度塌陷,按钮照样飘。
- 根容器(如
#app或body)必须设position: relative和min-height: 100vh(不能只写height: 100vh,否则键盘弹出时塌缩) - 底部区域加
width: 100%,否则横屏或缩放后偏移 - 聚焦时切为
position: absolute,并用window.innerHeight - inputRect.bottom计算bottom,不是写死数值
容易被忽略的底层细节
iOS 键盘收起后 window.innerHeight 不立即恢复;focusin 触发早于键盘完全展开;Safari 对 window.scrollTo() 有节流策略——这意味着延迟读取、阈值判断(比如检测 window.innerHeight 是否比初始值小 >200px)、手动锚点恢复(setTimeout(() => window.scrollTo(0, 0), 100))不是可选项,是必做动作。哪怕用了 visualViewportAPI 或 env(keyboard-inset-bottom),也得为老版本兜底,且不能跳过状态清理。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











