iOS软键盘导致fixed定位失效,应监听focusin/blur、用absolute+relative容器、结合env(keyboard-inset-bottom)降级处理,并注意viewport-fit=cover和坐标计算时机。

因为 iOS 把 position: fixed 锚定在「视觉视口(visual viewport)」底部,而软键盘弹出时它并不重算位置,只上推页面——结果就是按钮飘在半空、被顶出屏幕,不是你 CSS 写错了,是浏览器行为本身不可靠。
focusin/blur 是唯一靠谱的触发点,别碰 resize
监听 window.onresize 在 iOS Safari(尤其是 15.4+)中触发率低于 20%,且常只在键盘收起时才触发一次,完全漏掉弹出瞬间。真正该用的是 focusin(注意不是 focus,它冒泡更稳定)和 blur:
- 必须监听所有可聚焦元素:
input、textarea、[contenteditable],漏掉textarea就等于漏掉一半场景 -
focusin回调里要立刻检查document.activeElement === inputEl,防止异步焦点转移导致状态错位 -
blur回调里必须立刻清除内联样式:el.style.removeProperty('top')和el.style.removeProperty('bottom'),再恢复position: fixed和bottom: 0
absolute + relative 容器才是可控解法,但三条件缺一不可
只把 position: fixed 改成 position: absolute 会直接穿帮。必须同步满足:
- 根容器(如
#app或body)设position: relative和min-height: 100vh(不能只写height: 100%,否则键盘弹出时塌陷) - 底部元素加
width: 100%,否则横屏或缩放后偏移 -
focusin后用setTimeout(() => {}, 0)延迟读取getBoundingClientRect()——否则坐标仍是弹出前的旧值
计算 bottom 值用 window.innerHeight - inputRect.bottom,不是写死数值。
env(keyboard-inset-bottom) 能用但不能全靠它
bottom: env(keyboard-inset-bottom, 0px) 是 iOS Safari 16.4+ 原生支持的最优解,键盘弹出自动上浮,收起回退。但它有硬限制:
- 安卓完全不支持,旧版 Safari(如 15.3)也不识别
- 必须搭配
@supports (bottom: env(keyboard-inset-bottom))降级,否则整条规则被忽略 - 必须写 fallback:
bottom: env(keyboard-inset-bottom, 0px),不能只写env(keyboard-inset-bottom),否则键盘收起后按钮悬空 -
必须存在,否则不生效
最容易被忽略的是:所有坐标计算前,先确认 document.activeElement === inputEl;若页面用了 transform、overflow: hidden 或 position: fixed 父容器,getBoundingClientRect() 可能返回严重失真的坐标,且无任何报错提示。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











