最稳方案是flex + v-for:显式声明flex-wrap、子项宽33.333%、box-sizing: border-box、padding代替margin、数据补空项防断裂。

直接用 flex + v-for 实现最稳,别碰 uni-grid 插件或 grid 布局——小程序端兼容性差,H5 端表现不一致,反而拖慢上线节奏。
为什么 display: grid 在 uni-app 里基本不能用
微信小程序基础库低于 2.17.0 时完全不识别 display: grid;即使升级后,grid-template-columns: repeat(3, 1fr) 在部分安卓机上仍会塌陷成单列。H5 端虽支持,但 iOS Safari 对 gap 的解析和安卓 Chrome 不一致,导致间隙错位。跨端一致性要求高的业务(比如美团式分类菜单),必须放弃 grid。
flex-wrap + width: 33.333% 是唯一可靠组合
关键不是“怎么写”,而是“怎么防崩”:
-
flex-wrap: wrap必须显式声明,漏掉就会溢出容器不换行 - 子项宽度必须是固定值,如
width: 33.333%或flex: 0 0 33.333%,不能只写flex: 1—— iOS 微信里会错行 -
box-sizing: border-box必须加,否则padding会让实际宽度超 100%,最后一行只显示 1–2 个 - 间隙统一用
padding(父容器留边 + 子项内边距),别用margin,否则总宽超标触发异常换行
数据长度不是 3 的倍数?前端必须补空项
后端返回 list 长度为 7、8、10 是常态,不处理就会最后一行缺格子、样式断裂:
- 补空逻辑写在
computed里,例如:gridList() { const padded = [...this.rawList]; while (padded.length % 3) padded.push({ icon: '', text: '' }); return padded; } - 补的是空对象,不是
null或undefined,否则v-for渲染报错 - 若不想显示空格子,用
v-if="item.icon"控制显隐,但要同步把子项宽度改为calc(100% / 3),并确保父容器仍带flex-wrap
点击热区小、图标糊、文字截断的实战调法
美团这类高频点击菜单,体验细节决定留存:
-
hover-class必须设,hover-start-time="50"+hover-stay-time="50"让反馈更及时 - 图标用
image标签,mode="aspectFill",固定宽高(如64rpx × 64rpx),禁用scaleToFill - 文字用
text-overflow: ellipsis+white-space: nowrap防截断,字号建议 ≤24rpx - H5 端注意
rpx行为:App 端需确认manifest.json中app-plus节点是否启用 rpx 支持
真正卡住上线的,从来不是布局写法,而是数据没对齐、padding 没算进 box-sizing、以及 iOS 微信里那个神出鬼没的换行 bug——这些地方一错,九宫格就变成“七宫格”或“歪斜格”。











