Flex 与 Grid 布局完全指南

10 阅读11分钟

一篇讲透 display: flexdisplay: grid:从基本概念到每一个属性,全部附代码示例与效果说明,最后给出两者的对比与选型建议。


项目示例预览地址

codepen.io/editor/wang…

一、Flex 弹性布局

1.1 基本概念

Flex 是"一维"布局,只处理一个方向(主轴)上的排列。

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

关键概念:

  • 主轴(main axis):由 flex-direction 决定,默认水平(row),项目沿主轴排列;
  • 交叉轴(cross axis):与主轴垂直的方向;
  • 主起/主尾、交叉起/交叉尾:主轴和交叉轴的起点与终点;
  • 容器(flex container):设置 display: flex 的元素;
  • 项目(flex item):容器的直接子元素。
主轴方向(flex-direction: row)
┌──────────────────────────────────────┐
│  [item1]  [item2]  [item3]  [item4]  │ ← 项目沿主轴排列
│                                      │
│                                      │ ← 交叉轴方向(垂直)
└──────────────────────────────────────┘

示例

<div class="container">
  <div class="item">1</div>
  <div class="item">2</div>
  <div class="item">3</div>
</div>
.container {
  display: flex;
  background: #f0f4ff;
  padding: 16px;
}
.item {
  background: #409eff;
  color: #fff;
  width: 80px;
  height: 80px;
  margin: 8px;
  display: flex;
  justify-content: center;
  align-items: center;
}

1.2 容器属性(写在父元素上)

① flex-direction —— 主轴方向

取值效果
row(默认)水平从左到右
row-reverse水平从右到左
column垂直从上到下
column-reverse垂直从下到上
.container { flex-direction: row; }      /* 默认:→ → → */
.container { flex-direction: row-reverse; } /* ← ← ← */
.container { flex-direction: column; }   /* 竖排:↓↓↓ */
.container { flex-direction: column-reverse; } /* ↑↑↑ */

注意:row-reverse/column-reverse 不只是换方向,主轴的起点终点也互换,justify-content 的对齐起点会跟着变。

② flex-wrap —— 是否换行

取值效果
nowrap(默认)不换行,空间不足时项目被压缩
wrap换行,多行排列
wrap-reverse换行,且新行从交叉轴反向开始
.container { flex-wrap: wrap; }   /* 放不下就换到下一行 */
.container { flex-wrap: nowrap; } /* 默认,强行塞一行 */
.container { flex-wrap: wrap-reverse; } /* 换行且反向 */

③ flex-flow —— flex-direction + flex-wrap 简写

.container {
  /* flex-direction: row; flex-wrap: wrap; */
  flex-flow: row wrap;
}

④ justify-content —— 主轴方向的对齐

取值效果
flex-start(默认)靠主起点
flex-end靠主终点
center居中
space-between两端对齐,项目间间距相等
space-around每项两侧有相等的空间
space-evenly所有间隙完全相等
.container {
  display: flex;
  justify-content: space-between; /* 典型:导航栏左右分布 */
}
justify-content: space-between
[item1]          [item2]          [item3]

justify-content: space-evenly
   [item1]    [item2]    [item3]

⑤ align-items —— 交叉轴方向的对齐(单行)

取值效果
stretch(默认)拉伸填满交叉轴高度
flex-start靠交叉起点
flex-end靠交叉终点
center交叉轴居中
baseline按文字基线对齐
.container {
  display: flex;
  align-items: center; /* 最常用:垂直居中 */
}

经典实现水平垂直居中justify-content: center; align-items: center;

⑥ align-content —— 多行时交叉轴的对齐

flex-wrap: wrap 产生多行时才生效,取值同 justify-content(外加 stretch)。

.container {
  display: flex;
  flex-wrap: wrap;
  align-content: space-between; /* 多行整体在交叉轴分布 */
  height: 400px;
}

区别:align-items 控制"每一行内项目"的对齐;align-content 控制"多行整体"的分布。单行时 align-content 无效。

⑦ gap —— 项目间距

.container {
  display: flex;
  gap: 16px;            /* 行、列间距都是 16px */
  row-gap: 12px;        /* 行间距 */
  column-gap: 8px;      /* 列间距 */
}

gapmargin 更好用:不影响两端、不会把间距算进 flex-basis


1.3 项目属性(写在子元素上)

① order —— 排列顺序

数值越小越靠前,默认 0,可为负数。

.item-1 { order: 3; }
.item-2 { order: 1; }
.item-3 { order: 2; }
/* 显示顺序:item-2 → item-3 → item-1 */

② flex-grow —— 放大比例

默认 0(不放大)。当容器有剩余空间时,按比例分配。

.container { display: flex; width: 600px; }
.item { flex-grow: 1; }   /* 平均分剩余空间 */
.item-big { flex-grow: 2; } /* 占比是别的项目的 2 倍 */
剩余空间 300px
[ A:flex-grow 1 ][ B:flex-grow 2 ]A100pxB200px

③ flex-shrink —— 缩小比例

默认 1(空间不足时允许缩小)。设为 0 则不缩小(保持原尺寸,可能溢出)。

.item { flex-shrink: 0; }  /* 不缩小,宽度固定 */
.item { flex-shrink: 2; }  /* 空间不足时缩小的程度更大 */

④ flex-basis —— 初始主轴尺寸

项目在"放大/缩小之前"的基准尺寸,默认 auto(取自身 width/height)。

.item { flex-basis: 200px; } /* 先按 200px 算,再参与 grow/shrink */
.item { flex-basis: 50%; }

⑤ flex —— flex-grow flex-shrink flex-basis 简写

写法等价含义
flex: 11 1 0%等分剩余空间(最常用)
flex: auto1 1 auto按内容大小 + 参与伸缩
flex: none0 0 auto固定尺寸,不伸缩
flex: 0 1 auto默认可缩小不可放大
.sidebar { flex: 0 0 240px; } /* 固定 240px,不放大不缩小 */
.main { flex: 1; }            /* 占满剩余空间 */
/* 经典:侧边栏固定 + 主区自适应 */

⑥ align-self —— 单个项目在交叉轴的对齐

覆盖容器的 align-items,取值相同。

.container { align-items: center; }
.item-special { align-self: flex-end; } /* 只把这个项目放到底部 */

Flex 属性速查表

属性作用于常用取值
flex-direction容器row / column / ...reverse
flex-wrap容器nowrap / wrap
flex-flow容器direction + wrap
justify-content容器center / space-between / space-evenly
align-items容器center / stretch / baseline
align-content容器多行分布
gap容器间距
order项目排列顺序
flex-grow项目放大比例
flex-shrink项目缩小比例
flex-basis项目初始尺寸
flex项目三合一简写
align-self项目单项目对齐

二、CSS Grid 网格布局

2.1 基本概念

Grid 是"二维"布局,同时处理行和列

.container {
  display: grid; /* 或 inline-grid */
}

关键概念:

  • 网格线(grid line):划分网格的线,行线/列线;
  • 网格轨道(track):两条相邻线之间的行/列;
  • 网格单元(cell):行与列交叉的最小单位;
  • 网格区域(area):一个或多个单元格组成的矩形区域。
列线: 1        2       3        4
      │  100px │ 1fr   │ 1fr    │
行线 1┌────────┬────────┬────────┐
     │  cell  │  cell  │  cell  │
行线 2├────────┼────────┼────────┤
     │  cell  │  cell  │  cell  │
行线 3└────────┴────────┴────────┘

示例

<div class="grid">
  <div class="box">A</div>
  <div class="box">B</div>
  <div class="box">C</div>
  <div class="box">D</div>
</div>
.grid {
  display: grid;
  grid-template-columns: 100px 1fr 1fr; /* 3 列:固定 + 两列自适应 */
  grid-template-rows: 80px 80px;        /* 2 行 */
  gap: 12px;
}
.box {
  background: #409eff;
  color: #fff;
  display: grid;
  place-items: center; /* 单元格内居中 */
}

2.2 容器属性(写在父元素上)

① grid-template-columns / grid-template-rows —— 定义轨道

支持多种单位:

/* 固定值 */
.grid { grid-template-columns: 100px 200px 100px; }

/* 百分比 */
.grid { grid-template-columns: 25% 25% 50%; }

/* fr(fraction 分数单位):按比例瓜分剩余空间 */
.grid { grid-template-columns: 1fr 2fr 1fr; } /* 1:2:1 三列 */

/* repeat():重复 */
.grid { grid-template-columns: repeat(3, 1fr); } /* 等同 1fr 1fr 1fr */

/* minmax():最小-最大约束 */
.grid { grid-template-columns: minmax(200px, 1fr) 1fr; }
/* 第一列至少 200px,最多占满剩余 */

/* auto:按内容 */
.grid { grid-template-columns: auto 1fr; }
/* 行同理 */
.grid {
  grid-template-rows: 100px auto 1fr; /* 头 / 内容自适应 / 尾部占满 */
}

auto-fill 与 auto-fit —— 自动填充

.grid {
  display: grid;
  /* 每列至少 200px,能放几列放几列(自适应列数) */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  /* auto-fit 与 auto-fill 区别:项目少时 auto-fit 会把空轨道塌陷合并 */
}

② grid-template-areas —— 区域命名布局

.page {
  display: grid;
  grid-template-columns: 200px 1fr;
  grid-template-rows: 60px 1fr 60px;
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
}
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.content { grid-area: content; }
.footer  { grid-area: footer; }
┌──────────┬──────────┐
│ headerheader   │
├──────────┼──────────┤
│ sidebar  │ content  │
├──────────┼──────────┤
│ footerfooter   │
└──────────┴──────────┘

.(点)表示空单元格:grid-template-areas: "a . b";

③ gap —— 行列间距

.grid {
  display: grid;
  gap: 16px;          /* 行列统一 */
  row-gap: 12px;      /* 行间距 */
  column-gap: 8px;    /* 列间距 */
}

④ grid-auto-flow —— 项目自动放置规则

取值效果
row(默认)按行依次放置,放满一行换下一行
column按列依次放置
dense回填前面留下的空洞(可与 row/column 组合:row dense
.grid { grid-auto-flow: column; }  /* 纵向排列 */
.grid { grid-auto-flow: row dense; } /* 尽量紧凑,回填空洞 */

⑤ grid-auto-rows / grid-auto-columns —— 隐式轨道大小

显式轨道用 grid-template-* 定义;放不下的项目会创建"隐式轨道",用这组属性控制其大小。

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 80px;           /* 新增行的默认高度 */
  grid-auto-columns: 100px;       /* 新增列的默认宽度 */
}

⑥ justify-items / align-items —— 项目在单元格内的对齐

取值效果
stretch(默认)拉伸填满单元格
start起点(左/上)
end终点(右/下)
center居中
.grid {
  justify-items: center;  /* 水平居中 */
  align-items: center;    /* 垂直居中 */
  /* 简写 */
  place-items: center;    /* = justify-items + align-items */
}

⑦ justify-content / align-content —— 整个网格在容器内的对齐

当网格总尺寸小于容器(例如用固定像素定义轨道)时生效。

.grid {
  display: grid;
  grid-template-columns: 100px 100px; /* 总宽 200px < 容器 */
  justify-content: center;   /* 网格整体水平居中 */
  align-content: space-between; /* 网格整体垂直分布 */
  /* 简写 */
  place-content: center;
}

取值:start / end / center / stretch / space-between / space-around / space-evenly

⑧ grid-template —— 简写

.grid {
  /* grid-template-rows / grid-template-columns / grid-template-areas */
  grid-template:
    "header header" 60px
    "sidebar content" 1fr
    "footer footer" 60px
    / 200px 1fr;
}

2.3 项目属性(写在子元素上)

① grid-column / grid-row —— 按网格线定位

.item {
  /* 从第 1 列线到第 3 列线(占 2 列) */
  grid-column: 1 / 3;
  /* 从第 2 行线开始,跨越 2 行 */
  grid-row: 2 / span 2;
}

常用写法:

.item { grid-column: 1 / 3; }      /* 起线 / 止线 */
.item { grid-column: 1 / -1; }     /* -1 表示最后一条线,即占满整行 */
.item { grid-column: span 2; }     /* 跨越 2 列(不指定起线) */
.item { grid-column: 2; }          /* 单列简写 */
.item { grid-column: 1 / span 2; } /* 从线 1 开始跨 2 列 */

示例:一列跨两列

.grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}
.item-wide { grid-column: 1 / 3; } /* 占第 1、2 列 */

② grid-area —— 区域定位

两种用法:用 grid-template-areas 定义的名字,或四线定位。

/* 用法一:区域名(配合 grid-template-areas) */
.item { grid-area: sidebar; }

/* 用法二:四条网格线 row-start / column-start / row-end / column-end */
.item {
  grid-area: 1 / 1 / 3 / 3;
  /* 从第1行第1列 到 第3行第3列(占 2x2) */
}

③ justify-self / align-self / place-self —— 单个项目在单元格内对齐

.item {
  justify-self: center; /* 水平居中(覆盖 justify-items) */
  align-self: end;      /* 垂直靠下 */
  place-self: center;   /* 简写,单元格内居中 */
}

Grid 属性速查表

属性作用于作用
grid-template-columns/rows容器定义轨道(fr / repeat / minmax)
grid-template-areas容器区域命名布局
gap容器行列间距
grid-auto-flow容器自动放置规则(row/column/dense)
grid-auto-rows/columns容器隐式轨道大小
justify/align/place-items容器项目在单元格内对齐
justify/align/place-content容器网格整体对齐
grid-column/row项目按线定位、跨越
grid-area项目区域定位 / 四线定位
justify/align/place-self项目单项目对齐

三、Flex vs Grid:对比与选型

3.1 核心区别

对比项FlexGrid
维度一维(一个方向)二维(行 + 列)
设计思想内容驱动(项目伸缩填满)布局驱动(先画网格再放内容)
擅长单行/单列排列、对齐、居中等页面骨架、规则二维布局
跨行跨列不支持(同一轴线)原生支持(span / grid-area)
列数由内容决定由轨道定义决定

3.2 典型选型建议

优先用 Flex

/* 导航栏:一行水平分布 */
.nav { display: flex; justify-content: space-between; align-items: center; }

/* 按钮组 / 图标行 */
.toolbar { display: flex; gap: 8px; }

/* 垂直居中 */
.center { display: flex; justify-content: center; align-items: center; }

/* 固定侧栏 + 自适应主区 */
.sidebar { flex: 0 0 240px; }
.main { flex: 1; }

优先用 Grid

/* 页面整体骨架:二维区域划分 */
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "sidebar content"
    "footer footer";
}

/* 商品卡片网格:自动响应式列数 */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}

/* 九宫格 / 表格类布局 */
.board {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 100px;
  gap: 8px;
}

3.3 两者混用(最常用实践)

Grid 做整体骨架,用 Flex 做局部对齐

.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: 60px 1fr;
  grid-template-areas:
    "header header"
    "sidebar content";
  height: 100vh;
}
.header {
  grid-area: header;
  display: flex;               /* Grid 里再用 Flex */
  justify-content: space-between;
  align-items: center;
}
.content {
  grid-area: content;
  display: grid;               /* 内容区再嵌套 Grid */
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px;
}

3.4 常见面试追问

Q:Flex 和 Grid 能互相替代吗? 不能完全替代。Flex 擅长单维度的弹性排列与对齐;Grid 擅长二维的规则划分。复杂布局常两者组合使用。

Q:flex: 11fr 的区别?

  • flex: 1 是 flex-grow: 1,针对剩余空间按比例分配;
  • 1fr 是网格分数单位,针对整条轨道按比例分配。 两者都能实现自适应,但作用模型不同。

Q:什么时候用 place-items 什么时候用 place-content

  • place-items 控制项目在单元格内的位置;
  • place-content 控制整个网格在容器中的位置。

收藏这份指南,配合动手敲代码练习:先掌握 Flex 的一维思维,再掌握 Grid 的二维思维,两者结合基本能覆盖前端 99% 的布局场景。