直接用repeat(auto-fit, minmax(80px, 1fr))能适配多数手机底部导航,因auto-fit合并空轨道使图标均分容器,80px对应iOS@2x下≥44pt可点击热区,兼顾防误触与文字完整显示;须配width: 100%、min-height: 44px/48px及padding-bottom: env(safe-area-inset-bottom)确保真机可用。

为什么直接写 repeat(auto-fit, minmax(80px, 1fr)) 就能跑通大多数手机场景
因为这个组合天然适配「项数固定、屏幕宽度多变」的底部导航本质:auto-fit 会合并未填充的轨道,让已有导航项拉伸占满容器;minmax(80px, 1fr) 中的 80px 是 iOS @2x 屏下 ≥44pt 可点击区域的像素换算值,既防误触,又避免文字被 text-overflow: ellipsis 截断。
常见错误是把 minmax(40px, 1fr) 当“更小更灵活”,实测手指点击错误率上升 3 倍以上——安卓和 iOS 都会触发热区判定失败。
- 别用
clamp()替代:iOS 15.4 及以下不支持,而底部导航是强交互区,兼容性优先级高于弹性 - 若图标+文字常超 100px(如带 Badge 的“消息”),可升为
minmax(100px, 1fr) - 所有尺寸统一用
px,避开em或rem在系统字体缩放下的波动
父容器没设 width: 100% 是列数不稳定最常见原因
现象:横屏显示 5 个图标,竖屏却只出 2 个还留大片空白——不是 auto-fit 失效,而是 Grid 按内容宽度(比如文字撑开的宽度)计算轨道,不是按视口宽度。
尤其当导航嵌在 position: fixed 的 wrapper 里时,wrapper 默认 width 是 auto,不是 100%。
立即学习“前端免费学习笔记(深入)”;
- 必须加
width: 100%和max-width: 100%双保险 - 安全区
env(safe-area-inset-bottom)必须加在**直接父容器**(如footer或.bottom-nav)上,而不是body或内部链接上 - 用
padding-bottom: env(safe-area-inset-bottom)最稳妥,iOS 和 Android WebView 都识别
触控热区小、总点不到?Grid 占位 ≠ 真实热区
很多团队写了 grid-column: 1 / -1 就以为按钮铺满整行,结果手指一点就点到空白处——因为 a 标签自身没尺寸,display: contents 或 font-size: 0 还会让热区消失。
Grid 只管位置,不管热区。触控热区必须由元素盒模型真实撑开。
- 每个导航项必须设
min-height: 48px(Android)或44px(iOS) - 禁用
display: contents,它会让元素脱离盒模型,热区归零 -
gap和padding会叠加占用垂直空间:例如gap: 4px+padding: 8px 12px已占满 56px–64px 的标准底栏高度,再加border或line-height就会撑高容器
什么时候该用 grid-auto-flow: column?大多数时候不该用
底部导航本质是「水平排列 → 空间不足时换行」,不是竖排菜单。grid-auto-flow: column 会强制从上往下填满一列再换列,导致第 4 个项直接掉到第二行最顶部,破坏视觉流和 tab 顺序。
真正需要它的情况极少:仅当小屏下要改成抽屉式单列竖排(非默认底栏形态),才配合 grid-template-columns: 1fr + grid-auto-rows: auto 使用。
- 保持默认
grid-auto-flow: row,靠repeat(auto-fit, ...)控制换行时机 - 绝对别开
grid-auto-flow: row dense:一旦某个项加了grid-column: span 2(如“首页”加徽标),dense 会把后续项插进空隙,打乱阅读器顺序 - 媒体查询内定义
grid-template-areas是反模式,移动端应靠列数自适应,而非硬编码区域
grid-template-columns 也会在真机上失效。


















