Skip to content

深入理解 Flex 与 Grid 布局

全部属性详解、经典布局方案、Subgrid、容器查询与实战技巧

什么是 Flex 与 Grid 布局?

定义Flexbox(弹性盒布局)是 CSS3 引入的一维布局模型,擅长在单行或单列方向上分配空间和对齐元素。Grid(网格布局)是 CSS 的二维布局模型,可以同时控制行和列,适合构建复杂的页面整体结构。两者都会为子元素创建新的格式化上下文(FFC / GFC)。

涉及场景

  • 导航栏 / 工具栏:Flex 实现水平排列、间距均分、垂直居中
  • 卡片列表:Flex wrap 或 Grid auto-fill 实现响应式多列卡片
  • 圣杯 / 双飞翼布局:Grid 几行代码替代传统浮动方案
  • Dashboard 面板:Grid 的命名区域(grid-template-areas)实现仪表盘布局
  • 表单对齐:Grid 让 label 和 input 完美对齐
  • 垂直居中display: flex; align-items: center; justify-content: center 一行居中

作用

  1. 告别浮动时代:Flex 和 Grid 彻底替代了 float + clearfix 的布局方式
  2. 简化响应式:配合 minmax()auto-fill、容器查询,少量代码实现自适应
  3. 精确控制:对齐、间距、比例分配、自动填充都有专用属性,不再需要 hack
  4. 面试必考:Flex 的 flex: 1 含义、Grid 的 fr 单位是高频考题

Flexbox 完整指南

容器属性(父元素)

css
.container {
  display: flex; /* 或 inline-flex */

  /* 1. flex-direction:主轴方向 */
  flex-direction: row;            /* 默认:水平从左到右 */
  flex-direction: row-reverse;    /* 水平从右到左 */
  flex-direction: column;         /* 垂直从上到下 */
  flex-direction: column-reverse; /* 垂直从下到上 */

  /* 2. flex-wrap:是否换行 */
  flex-wrap: nowrap;    /* 默认:不换行(可能压缩子元素) */
  flex-wrap: wrap;      /* 换行 */
  flex-wrap: wrap-reverse; /* 反向换行 */

  /* 3. flex-flow:direction + wrap 简写 */
  flex-flow: row wrap;

  /* 4. justify-content:主轴对齐 */
  justify-content: flex-start;    /* 默认:起点对齐 */
  justify-content: flex-end;      /* 终点对齐 */
  justify-content: center;        /* 居中 */
  justify-content: space-between; /* 两端对齐,间距相等 */
  justify-content: space-around;  /* 每个元素两侧间距相等 */
  justify-content: space-evenly;  /* 所有间距完全相等 */

  /* 5. align-items:交叉轴对齐(单行) */
  align-items: stretch;     /* 默认:拉伸填满 */
  align-items: flex-start;  /* 交叉轴起点 */
  align-items: flex-end;    /* 交叉轴终点 */
  align-items: center;      /* 交叉轴居中 */
  align-items: baseline;    /* 基线对齐 */

  /* 6. align-content:多行对齐(仅 wrap 时有效) */
  align-content: stretch;       /* 默认 */
  align-content: flex-start;
  align-content: flex-end;
  align-content: center;
  align-content: space-between;
  align-content: space-around;
  align-content: space-evenly;

  /* 7. gap:间距(替代 margin) */
  gap: 10px;          /* 行列间距相同 */
  gap: 10px 20px;     /* 行间距 列间距 */
  row-gap: 10px;
  column-gap: 20px;
}

子元素属性

css
.item {
  /* 1. order:排列顺序(默认0,越小越前) */
  order: -1; /* 排到最前面 */
  order: 1;  /* 排到后面 */

  /* 2. flex-grow:放大比例(默认0,不放大) */
  flex-grow: 0;  /* 默认:不占据剩余空间 */
  flex-grow: 1;  /* 等比例分配剩余空间 */
  flex-grow: 2;  /* 分配的空间是 flex-grow:1 的两倍 */

  /* 3. flex-shrink:缩小比例(默认1,等比例缩小) */
  flex-shrink: 0; /* 不缩小(常用于固定宽度元素) */
  flex-shrink: 1; /* 默认:等比例缩小 */

  /* 4. flex-basis:初始大小(默认auto) */
  flex-basis: auto;  /* 默认:使用 width/height */
  flex-basis: 0;     /* 忽略内容大小,完全按 grow 分配 */
  flex-basis: 200px; /* 固定初始宽度 */
  flex-basis: 30%;   /* 百分比 */

  /* 5. flex:简写(推荐使用简写) */
  flex: 0 1 auto;     /* 默认:不放大,可缩小,自动大小 */
  flex: 1;            /* = flex: 1 1 0%(等分空间) */
  flex: auto;         /* = flex: 1 1 auto */
  flex: none;         /* = flex: 0 0 auto(固定大小) */
  flex: 0 0 200px;    /* 固定200px,不伸缩 */

  /* 6. align-self:单个元素的交叉轴对齐 */
  align-self: auto;       /* 默认:继承 align-items */
  align-self: flex-start;
  align-self: flex-end;
  align-self: center;
  align-self: stretch;
  align-self: baseline;
}

flex 计算过程

css
/* 
剩余空间 = 容器大小 - 所有 flex-basis 之和

flex-grow 分配:
  每个元素获得 = (剩余空间 > 0) ? 剩余空间 * (自身grow / 总grow) : 0
  最终大小 = flex-basis + 获得的空间

flex-shrink 分配(空间不足时):
  需要缩小的总量 = |剩余空间|
  每个元素缩小 = 需要缩小总量 * (自身shrink * basis / Σ(shrink_i * basis_i))
  最终大小 = flex-basis - 缩小量
*/

/* 示例:容器 600px,三个子元素 */
.container { width: 600px; display: flex; }
.a { flex: 1 1 100px; }  /* basis: 100px, grow: 1 */
.b { flex: 2 1 100px; }  /* basis: 100px, grow: 2 */
.c { flex: 1 1 200px; }  /* basis: 200px, grow: 1 */

/* 
剩余空间 = 600 - (100 + 100 + 200) = 200px
总 grow = 1 + 2 + 1 = 4

.a = 100 + 200 * (1/4) = 100 + 50 = 150px
.b = 100 + 200 * (2/4) = 100 + 100 = 200px
.c = 200 + 200 * (1/4) = 200 + 50 = 250px
总计 = 600px ✅
*/

Grid 完整指南

容器属性

css
.grid {
  display: grid; /* 或 inline-grid */

  /* 1. 定义列和行 */
  grid-template-columns: 200px 1fr 200px;         /* 三列 */
  grid-template-columns: repeat(3, 1fr);           /* 三等分 */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* 自动填充 */
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));  /* 自动适应 */
  grid-template-columns: [start] 1fr [mid] 2fr [end]; /* 命名网格线 */

  grid-template-rows: 60px 1fr 40px;              /* 头-主体-底部 */
  grid-template-rows: repeat(3, minmax(100px, auto)); /* 最小100px */

  /* 2. 区域命名 */
  grid-template-areas:
    "header  header  header"
    "sidebar content content"
    "footer  footer  footer";

  /* 3. 间距 */
  gap: 10px 20px;      /* 行间距 列间距 */
  row-gap: 10px;
  column-gap: 20px;

  /* 4. 隐式网格(超出模板的自动行列) */
  grid-auto-rows: minmax(100px, auto);  /* 自动行的高度 */
  grid-auto-columns: 1fr;
  grid-auto-flow: row;      /* 默认:先填行 */
  grid-auto-flow: column;   /* 先填列 */
  grid-auto-flow: dense;    /* 紧密填充(填补空洞) */

  /* 5. 对齐 */
  justify-items: stretch;   /* 单元格内水平对齐(默认拉伸) */
  align-items: stretch;     /* 单元格内垂直对齐 */
  place-items: center;      /* 简写:align-items justify-items */

  justify-content: start;   /* 整个网格在容器中的水平对齐 */
  align-content: start;     /* 整个网格在容器中的垂直对齐 */
  place-content: center;    /* 简写 */

  /* 6. grid-template 简写 */
  grid-template:
    "header header" 60px
    "sidebar content" 1fr
    "footer footer" 40px
    / 200px 1fr;
}

子元素属性

css
.item {
  /* 1. 指定位置 */
  grid-column-start: 1;
  grid-column-end: 3;       /* 跨越第1-2列 */
  grid-column: 1 / 3;       /* 简写 */
  grid-column: 1 / span 2;  /* 从第1列开始,跨越2列 */
  grid-column: 1 / -1;      /* 从第1列到最后一列 */

  grid-row-start: 1;
  grid-row-end: 4;
  grid-row: 1 / 4;          /* 跨越第1-3行 */

  /* 2. 区域定位 */
  grid-area: header;         /* 匹配 grid-template-areas 中的名称 */
  grid-area: 1 / 1 / 3 / 3; /* row-start / col-start / row-end / col-end */

  /* 3. 单元格对齐 */
  justify-self: start | end | center | stretch;
  align-self: start | end | center | stretch;
  place-self: center;

  /* 4. 命名网格线定位 */
  grid-column: start / end;  /* 使用之前命名的网格线 */
}

fr 单位与 minmax()

css
/* fr = fraction(可用空间的份数) */
.grid {
  /* 可用空间 = 容器宽度 - gap - 固定宽度列 */
  grid-template-columns: 200px 1fr 2fr;
  /* 第一列200px,剩余空间1:2分配 */
}

/* minmax(min, max) */
.grid {
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  /* 每列最少200px,最大等分剩余空间 */
  /* auto-fill: 尽可能多的列(空的也占位) */
  /* auto-fit: 尽可能多的列(空的折叠为0) */
}

/* auto-fill vs auto-fit 区别 */
/* 容器 1000px,每项 minmax(200px, 1fr),只有3个子元素 */
/* auto-fill: 创建5列(2个空列占位),每列200px */
/* auto-fit: 创建3列,每列 333px(空列折叠,剩余空间分配给现有列) */

Subgrid(子网格,CSS Grid Level 2)

css
.parent {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto auto;
  gap: 10px;
}

.child {
  grid-column: 1 / 4; /* 跨越3列 */
  display: grid;
  /* subgrid 继承父网格的轨道定义 */
  grid-template-columns: subgrid;  /* 使用父网格的列轨道 */
  grid-template-rows: subgrid;     /* 使用父网格的行轨道 */
  /* 子元素会对齐到父网格的网格线 */
}

/* 典型应用:卡片列表中标题/内容/按钮对齐 */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 20px;
}

.card {
  display: grid;
  grid-template-rows: subgrid; /* 每张卡片的行高与其他卡片对齐 */
  grid-row: span 3;            /* 每张卡片占3行(标题+内容+按钮) */
}

经典布局方案

水平垂直居中

css
/* 方案1:Flex */
.center-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 方案2:Grid */
.center-grid {
  display: grid;
  place-items: center;
}

/* 方案3:Grid + margin */
.center-grid-margin {
  display: grid;
}
.center-grid-margin > .child {
  margin: auto;
}

/* 方案4:position + transform(不需要知道子元素尺寸) */
.center-pos {
  position: relative;
}
.center-pos > .child {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

/* 方案5:position + inset + margin(已知或不定尺寸均可) */
.center-inset {
  position: relative;
}
.center-inset > .child {
  position: absolute;
  inset: 0;
  margin: auto;
  width: fit-content;
  height: fit-content;
}

圣杯布局(Holy Grail)

css
/* Grid 方案(推荐) */
.holy-grail {
  display: grid;
  grid-template:
    "header header header" 60px
    "nav    main   aside" 1fr
    "footer footer footer" 40px
    / 200px 1fr 200px;
  min-height: 100vh;
}

.header { grid-area: header; }
.nav    { grid-area: nav; }
.main   { grid-area: main; }
.aside  { grid-area: aside; }
.footer { grid-area: footer; }

/* 响应式:小屏单列 */
@media (max-width: 768px) {
  .holy-grail {
    grid-template:
      "header" 60px
      "main"   1fr
      "nav"    auto
      "aside"  auto
      "footer" 40px
      / 1fr;
  }
}

瀑布流布局

css
/* CSS columns 方案 */
.masonry-columns {
  column-count: 3;
  column-gap: 16px;
}
.masonry-columns .item {
  break-inside: avoid;
  margin-bottom: 16px;
}

/* CSS Grid masonry(实验性,Firefox 支持) */
.masonry-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  grid-template-rows: masonry; /* 实验性 */
  gap: 16px;
}

等高列

css
/* Flex 自动等高 */
.equal-height {
  display: flex;
  gap: 20px;
}
.equal-height .column {
  flex: 1;
  /* align-items 默认 stretch,所有列自动等高 */
}

/* Grid 自动等高 */
.equal-height-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  /* 同一行的所有单元格自动等高 */
}
css
/* Flex 方案 */
body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main {
  flex: 1; /* 占据剩余空间 */
}
footer {
  /* 自动粘在底部 */
}

/* Grid 方案 */
body {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

Flex vs Grid 选择指南

场景推荐方案原因
一维排列(导航栏、工具栏)Flex一维布局更简单
表单布局Grid标签和输入框对齐
卡片列表Grid + auto-fill自动响应式
圣杯/双飞翼布局Grid二维布局直观
居中Grid place-items最简洁
等间距分布Flex space-between语义清晰
不规则布局Grid可命名区域
内容驱动(大小不确定)Flex自动伸缩
布局驱动(结构固定)Grid精确控制
总结:
• Flex = 一维(行或列),内容优先
• Grid = 二维(行和列),布局优先
• 实际项目中经常混合使用
• Grid 做页面整体布局,Flex 做组件内部布局

总结

Flex & Grid 核心知识点:
┌──────────────────────────────────────────────────────────┐
│ Flexbox                                                   │
│ • 容器:direction / wrap / justify / align / gap          │
│ • 子元素:grow / shrink / basis / order / align-self      │
│ • flex: 1 = flex: 1 1 0%                                 │
│ • 计算:剩余空间 = 容器 - Σbasis,按 grow/shrink 分配       │
├──────────────────────────────────────────────────────────┤
│ Grid                                                      │
│ • 模板:template-columns/rows / template-areas            │
│ • 定位:grid-column/row / grid-area                       │
│ • 函数:repeat() / minmax() / auto-fill / auto-fit        │
│ • fr 单位:可用空间的份数                                   │
│ • Subgrid:子网格继承父网格轨道                              │
├──────────────────────────────────────────────────────────┤
│ 选择原则                                                   │
│ • 一维选 Flex,二维选 Grid                                  │
│ • 内容驱动选 Flex,布局驱动选 Grid                           │
│ • 混合使用:Grid 做骨架,Flex 做组件                         │
└──────────────────────────────────────────────────────────┘