用 flex 实现 tabbar 底部布局的核心是让页面成为 column 方向弹性容器,main 区域 flex: 1 占满剩余空间,tabbar 作为固定高度兄弟元素自然被“顶”到底部,避免 fixed 定位的遮挡与软键盘错位问题。

用 display: flex 实现移动端底部 TabBar 固定布局,核心不是让 TabBar 自己“固定”,而是让整个页面成为垂直弹性容器,由内容区主动撑开、把 TabBar “顶”到底部——这样既避开 position: fixed 的遮挡和软键盘错位问题,又保持文档流完整性。
为什么不能直接给 TabBar 设 flex: 1
因为 flex: 1 只对弹性容器的**直接子元素**生效,且依赖父容器有明确高度约束。TabBar 本身是底部固定高度组件(比如 height: 60px),不该伸缩;真正该占满剩余空间的是它的兄弟元素(如 <main></main>)。
- 父容器(
或外层<div class="app">)必须设 <code>display: flex; flex-direction: column; min-height: 100vh -
<main></main>加flex: 1,它会自动填满除 TabBar 外的所有可用高度 - TabBar 作为最后一个子元素,不写
flex,只设height或min-height(避免 iOS Safari 对flex: 0 0 auto的兼容问题) - 别用
height: 100vh—— iOS Safari 地址栏显示/隐藏时,vh值会跳变;优先用min-height: 100vh或100dvh(需检查 Android WebView 兼容性) - TabBar 容器设
display: flex,子项(每个<button></button>或<a></a>)用flex: 0 0 20%(五格就写 20%,四格写 25%) - 加
min-width: 0到子项,防止长文字强制拉宽导致不均 - 子项内部用
display: flex; flex-direction: column; align-items: center;排图标+文字,别依赖text-align: center控制块级元素 - 避免
width: fit-content+margin: 0 auto—— 微信 WebView 和部分 Android 浏览器会失效 - 在
中必须加:<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">,否则env(safe-area-inset-bottom)返回0 - TabBar 容器加两条声明(兼容旧 iOS):
padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); - 不要在
calc()里混单位,Safari 15.4 之前不支持calc(60px + env(safe-area-inset-bottom));稳妥做法是单独设height: 60px,再叠加padding-bottom - 安卓和旧 iOS 会忽略
env(),自动 fallback 为0,无副作用 -
<main></main>必须设overflow-y: auto(或scroll),并确保其父容器(即 flex 容器)没有overflow: hidden - 不要给
<main></main>设height: calc(100vh - 60px)—— 软键盘弹出会改变视口高度,导致计算失真 - 微信 WebView 中,
visualViewportAPI 支持有限,建议监听focus/blur事件,动态给<main></main>加padding-bottom(值取document.documentElement.clientHeight - window.innerHeight) - 如果用了
100dvh,注意部分低版本 Chrome 不支持,需 JS fallback
TabBar 内部按钮怎么等宽又不被文字撑开
用 justify-content: space-around 在无宽度约束的容器里容易错位;flex: 1 在 <button></button> 上 iOS Safari 表现不稳定。更可控的方式是显式分配比例。
如何适配 iPhone X+ 的安全区(Home Indicator)
只写 bottom: 0 会让 TabBar 沉进手势条下面,用户点不到。关键不是调位置,而是预留空间。
软键盘弹出后 TabBar 错位或遮挡输入框怎么办
这是 position: fixed 方案的通病,而 flex 布局天然规避了这个问题——但前提是主内容区域可滚动且高度计算不依赖视口动态变化。
最易被忽略的一点:flex 布局下 TabBar 的定位本质是“文档流内推底”,所以它永远随页面滚动而滚动——这不是 bug,是预期行为;若真需要悬浮效果(比如吸顶搜索栏那种),那已超出 flex 能力范围,得换方案。











