Grid 还是 Flex?一张场景决策表 + 混用时最容易踩的 3 个布局坑

Grid 和 Flex 不是二选一的竞争关系,而是二维与一维的分工。本文先给一张「什么时候用 Grid、什么时候用 Flex」的场景决策表,再拆解两者混用时最常见的三个布局错误:用 flex 属性控制 grid 子项、justify-content 覆盖 justify-items 的居中错觉、以及 grid-template-columns 与 minmax 不当导致的溢出。每个错误都附一行修复方案与排查思路。

约 7 分钟读完 · 更新于 2026-10-21 · 文中每条都能在下面的配套工具里动手验证

一句话结论:一维用 Flex,二维用 Grid

先记结论再往下看:当你只关心「一行或一列上怎么排」用 Flex;当你需要「行和列同时约束」用 Grid。两者还可以嵌套混用——Grid 负责页面骨架,Flex 负责骨架内部的对齐,这才是生产环境的常见分工。

典型分工:Grid 搭骨架,Flex 管内容
/* Grid:页面级二维骨架 */
.layout {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto; /* 头 / 主体 / 尾 */
}

/* Flex:单元格内的一维排列 */
.card {
  display: flex;          /* 一行内对齐 */
  justify-content: space-between;
  align-items: center;
}

场景决策表

拿不准的时候直接对号入座,命中哪行用哪个:

场景推荐原因
导航栏、工具条等一行内排列Flex本质是一维分布,Flex 更简单直接
卡片瀑布流、等宽等高网格Gridrepeat + auto-fill 一行搞定换行与等宽
整页布局(头/侧栏/主体/尾)Grid行列同时约束,天然二维骨架
表单 label 与输入框对齐Flex单行两端对齐是 Flex 强项
卡片内部「标题 + 按钮」对齐Flex卡片内部通常是一维内容
不规则拼图、跨行跨列布局Gridgrid-row/column span 是唯一解
内容宽度未知、需要内容决定尺寸Flexflex-basis 按内容伸缩更自然

混用错误一:在 Grid 子项上写 flex 属性

最常见的手滑:容器是 display: grid,却给子项写 flex: 1 或 flex-direction,期望它们「伸缩」。Grid 子项完全忽略这些属性,于是布局纹丝不动。先看容器 display 再决定用哪套属性——子项的属性永远由父容器决定。

错误写法
/* 容器是 grid,子项的 flex 系列属性全部无效 */
.list { display: grid; grid-template-columns: 1fr 1fr; }
.list > .item { flex: 1; flex-direction: column; } /* 没有任何效果 */
一行修复
/* grid 子项要伸缩用 minmax/fr,或把子项自身设为 flex 容器 */
.list > .item { display: flex; flex-direction: column; } /* 子项内部用 flex,合法 */

混用错误二:justify-content 造成的「居中失效」错觉

Grid 里 justify-content 分配的是「网格整体在容器里的位置」,justify-items 才是「子项在自己格子里的位置」。从 Flex 过来的人习惯性写 justify-content: center,结果发现每列内容还是顶着格子左边——那是因为网格轨道已经占满容器,content 没有多余空间可分。

想让子项在格子里居中
.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  justify-items: center;    /* 子项在各自格内水平居中 */
  align-items: center;      /* 垂直居中 */
}

混用错误三:minmax 用错导致横向溢出

自适应卡片列最推荐 auto-fill + minmax,但很多人把最小值写成固定像素又忘了 1fr 上限的语义,或者直接用 minmax(300px, 300px) 当固定列。真正的一行修复是 minmax(min, 1fr):小屏收窄到 min,大屏均分剩余空间。再配合 min-width: 0 防止长单词把轨道撑爆。

响应式卡片列的黄金写法
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
.cards > * {
  min-width: 0;  /* 防 grid 子项默认 min-width:auto 溢出 */
  overflow: hidden;
}

混用的三条安全原则

混用不是禁区,乱混才是。守住这三条,Grid 与 Flex 可以在任何项目里和平共处:

  1. 看容器的 display 决定属性集:grid 容器用 grid-* 与 place-*,flex 容器用 flex-direction/order/flex 属性,两套互不越界。
  2. 布局按层级分工:外层 Grid 管页面骨架与大区块位置,内层 Flex 管组件内部的一行排列,最多嵌套两层。
  3. 改布局先改容器再改子项:布局不动时先在 DevTools 里确认「我改的属性属于哪一层」,90% 的混用错误都发生在改错了层。

布局不动的快速排查清单

属性写了却毫无反应时,按顺序过一遍这张清单,通常两分钟内定位问题:

  • 容器 display 是 grid 还是 flex?子项属性必须匹配容器类型。
  • justify-content 与 justify-items / align-content 与 align-items 是不是选错了?Grid 里它们含义不同。
  • 子项是否带有 min-width/min-height 默认 auto 导致撑开轨道或溢出?加 min-width: 0 试试。
  • 是否在 grid 子项上写 flex-direction / order?order 在 grid 里其实有效,但 flex-direction 无效。
  • gap 是否被 margin 叠加干扰?grid 里用 gap 就别再给子项加外边距。

决策流程:三步定工具

把选择收敛成一个可重复的流程,每次新布局都套一遍:

  1. 问「行和列需要同时约束吗」:需要 → Grid;只约束一个方向 → 进下一步。
  2. 问「子项数量与内容宽度是否已知」:固定几个已知宽度 → Flex 足够;数量不定、需要自动换行均分 → Grid。
  3. 定骨架后自检:容器属性集与 display 是否匹配、子项是否误用了另一套属性、是否有 min-width:auto 溢出隐患,三项都过即可交付。

常见问题

Grid 容器的子项上写 flex: 1 为什么没反应?

因为子项属性由父容器的 display 决定。父容器是 display: grid 时,子项的 flex、flex-direction 等 Flex 属性会被完全忽略。想让子项内部用 Flex,应把子项自身设为 display: flex。

卡片列表到底该用 Grid 还是 Flex?

要求等宽等高、自动换行且列数随屏幕自适应时用 Grid(auto-fill + minmax);若卡片数量固定、宽度由内容决定,用 Flex + flex-wrap 更简单。多数商品/文章卡片列表首选 Grid。

justify-content: center 在 Grid 里居中不了子项?

Grid 的 justify-content 控制整个网格在容器中的位置,不是子项在格子里的位置。轨道已被 1fr 撑满时它无空间可分。让子项在格内居中应使用 justify-items: center 或 align-items: center。

Grid 和 Flex 能嵌套使用吗?

不仅能,而且推荐。常见分工是外层 Grid 搭页面骨架(侧栏、主区、页脚),每个区块内部用 Flex 做一维对齐。控制在两层嵌套内,属性集不越界,维护成本最低。

📂

松开以自动格式化

支持 .json / .sql / .csv / .html / .css / .xml / .yaml 文件