首选 position: sticky 替代 fixed,父容器设 min-height: 100vh 和 overflow-y: auto,按钮设 position: sticky; bottom: 0;ios 16.4+ 可用 env(keyboard-inset-bottom) 纯 css 避让;兼容旧版可用 absolute + focusin/blur 动态适配;flex 布局(dvh + flex: 1)结构最稳。

直接修 position: fixed 是无效的——它被键盘顶起不是因为你漏写了 z-index 或写错了 bottom,而是浏览器把 fixed 锚定在初始 visualViewport 上,键盘一弹,视口高度变了,但定位值不重算。必须换锚点、换布局,或用环境变量/JS 动态干预。
用 position: sticky 替代 fixed(推荐首选)
适用于按钮紧贴内容流底部的场景(如聊天输入框旁的「发送」、评论区提交栏),不脱离文档流,天然避开键盘错位问题:
- 父容器需设
min-height: 100vh且允许内部滚动(overflow-y: auto) - 按钮自身设
position: sticky; bottom: 0;,别加transform或filter到祖先上,否则 sticky 失效 - 避免给父容器设
overflow: hidden或display: flex同时又没配flex-direction: column,这会让 sticky 认为“没有可滚动空间”而退化为 static - iOS 15.4+ / Android Chrome 90+ 均支持;旧版可用
@supports not (position: sticky)降级为position: absolute; bottom: 0;
用 env(keyboard-inset-bottom) 做 iOS 原生避让(仅限 iOS 16.4+)
这是目前最干净的纯 CSS 方案,但有硬性前提,缺一不可:
-
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">必须存在 - 样式必须包裹在
@supports (bottom: env(keyboard-inset-bottom))里,否则旧版 Safari 可能整条规则失效 - 写法只能是
bottom: env(keyboard-inset-bottom, 0px);——不能混用svh,比如calc(100svh - 100%)或env(keyboard-inset-bottom) + 10px都会出错 - 安卓完全不支持该变量,必须搭配 fallback,例如
@supports not (bottom: env(keyboard-inset-bottom)) { .btn { position: sticky; bottom: 0; } }
用 position: absolute + focusin/blur 动态适配(兼容性最广)
覆盖所有 iOS 版本和老安卓 WebView,但必须同时满足三个条件,只改一个属性必失败:
- 根容器(如
#app或body)设position: relative和min-height: 100vh(不能只写height: 100%,否则键盘弹出时塌陷) - 底部元素加
width: 100%,否则横屏或缩放后左右偏移 - 监听
focusin(不是focus)到所有input和textarea,并在回调里用setTimeout(() => { ... }, 0)延迟读取getBoundingClientRect(),否则拿到的是键盘未展开前的坐标 -
blur后立刻恢复position: fixed并清除内联top/bottom,否则滚动时定位彻底错乱
用 flex 布局把“固定效果”做进文档流(结构最稳)
不依赖视口,靠父容器尺寸和布局规则推导位置,键盘弹起时位置不变:
- 根容器设
display: flex; flex-direction: column; min-height: 100dvh(dvh在 iOS 16.4+/Chrome 109+ 支持,会随键盘自动调整;不支持时 fallback 到100vh) - 主内容区用
flex: 1占满剩余空间,底部区域用flex-shrink: 0防止被压缩 - 底部元素必须是普通块级元素,不能是
position: fixed,也不能嵌套在 flex 容器内部再设align-self: flex-end——那只是视觉上“看起来在下面”,仍可能被键盘顶起 - 慎用
body { overflow: hidden },iOS Safari 下可能阻止键盘弹起时的必要滚动
最容易被忽略的是:多个输入框共用同一底部栏时,焦点切换频繁,focusin 和 blur 可能交错触发,导致定位状态混乱。必须用全局变量记录 document.activeElement,并在每次 focusin 前检查是否已处理,否则按钮会在 fixed/absolute 间反复横跳。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











