跳到主要内容

Grid 布局

面试速答(30 秒版 TL;DR)

  • Grid(CSS Grid Layout)是 二维布局系统:可以同时控制列(column)和行(row);Flex 更偏 一维布局
  • 最稳的答法是 4 句话:
    • 容器先定义 轨道(tracks)grid-template-columnsgrid-template-rows
    • 子项再决定 放在哪些格子grid-columngrid-rowgrid-area
    • 空间不够时会生成 隐式网格(implicit grid)grid-auto-*
    • 对齐分两层:单元格内对齐justify-items/align-items整个轨道组在容器内对齐justify-content/align-content
  • Grid 高频函数/关键字:
    • repeat()minmax()fit-content()
    • frauto-fillauto-fitspan
    • 命名网格线 [name]、命名区域 grid-template-areas
  • 工程高频场景:后台骨架、圣杯布局、卡片墙、看板、相册矩阵、响应式网格。

心智模型

把 Grid 想成:

先画棋盘,再决定每个元素占哪几格;最后再决定格子里的元素怎么对齐。

所以 Grid 的题,永远按这条线回答最稳:

  1. 网格怎么画:几列几行,显式还是隐式。
  2. 元素怎么放:从哪条线开始,到哪条线结束,是否跨行跨列。
  3. 剩余空间怎么分frminmax()auto-fit/auto-fill
  4. 元素怎么对齐:单元格内对齐 vs 整体轨道对齐。

一、先把 6 个基础概念说清楚

1)网格容器(grid container)和网格项(grid item)

  • 父元素设置 display: griddisplay: inline-grid 后,就是网格容器
  • 直接子元素就是网格项
.layout {
display: grid; /* 块级 grid 容器 */
}

.inlineLayout {
display: inline-grid; /* 容器本身按行内级盒子参与外部排版 */
}

2)轨道(track)

  • 一列就是一个列轨道(column track)
  • 一行就是一个行轨道(row track)

3)网格线(grid line)

  • 每条轨道边界都是一条线
  • grid-column: 2 / 4 的意思,不是“第 2 列到第 4 列”,而是“从第 2 条列线到第 4 条列线

4)单元格(cell)

  • 行和列交叉形成的最小格子

5)区域(area)

  • 多个相邻单元格组成一个网格区域
  • grid-area 既可以引用命名区域,也可以直接写起止线的简写

6)显式网格(explicit grid)和隐式网格(implicit grid)

  • 你手动写出来的 grid-template-columnsgrid-template-rows 属于显式网格
  • 项目放不下、或者你把子项放到显式网格之外时,浏览器会自动补出隐式网格
  • 隐式网格的尺寸由 grid-auto-columnsgrid-auto-rows 控制

二、容器属性(Container)完整清单

这一部分最容易答散。建议按“画网格 -> 补隐式网格 -> 做间距 -> 做对齐 -> 简写”来讲。

1)开启 Grid:display

.grid {
display: grid;
}

.inlineGrid {
display: inline-grid;
}
  • grid:容器本身是块级盒子
  • inline-grid:容器本身是行内级盒子,但内部子项仍按 Grid 算法布局

2)定义显式列轨道:grid-template-columns

.cards {
display: grid;
grid-template-columns: 240px 1fr 2fr;
}

含义:

  • 第 1 列固定 240px
  • 后两列按剩余空间按 1:2 分配

常见值:

  • 固定长度:200px
  • 百分比:25%
  • 内容尺寸:automax-contentmin-content
  • 剩余空间份额:fr
  • 函数:repeat()minmax()fit-content()
  • Level 2 常见值:subgrid

3)定义显式行轨道:grid-template-rows

.page {
display: grid;
grid-template-rows: 64px 1fr auto;
}

这个写法很适合页面骨架:

  • 第一行头部固定高
  • 第二行主内容吃剩余空间
  • 第三行底部高度由内容决定

4)命名区域:grid-template-areas

.dashboard {
display: grid;
grid-template-columns: 220px minmax(0, 1fr);
grid-template-rows: 64px 1fr;
grid-template-areas:
"header header"
"sidebar main";
}

.header {
grid-area: header;
}

.sidebar {
grid-area: sidebar;
}

.main {
grid-area: main;
min-width: 0;
}

规则要点:

  • 每一行字符串的列数必须一致
  • . 表示空白单元格
  • 同名区域必须组成一个 矩形
  • 这个属性表达力很强,特别适合页面骨架题

5)grid-template 简写

它是下面 3 个属性的简写:

  • grid-template-rows
  • grid-template-columns
  • grid-template-areas

示例:

.layout {
display: grid;
grid-template:
"header header" 64px
"sidebar main" 1fr
/ 220px minmax(0, 1fr);
}

面试里知道它是简写即可,工程里拆开写通常更清楚。

6)隐式列轨道尺寸:grid-auto-columns

.gallery {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-auto-columns: 120px;
}

当你把某个元素放到显式列以外时,新补出来的隐式列宽度由它决定。

7)隐式行轨道尺寸:grid-auto-rows

.list {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-rows: minmax(80px, auto);
}

这是很高频的写法:自动生成的新行至少 80px 高,内容多时可以继续撑开。

8)自动放置规则:grid-auto-flow

.autoFlow {
display: grid;
grid-template-columns: repeat(3, 1fr);
grid-auto-flow: row;
}

常见值:

  • row:默认值,先按行填,放满一行再去下一行
  • column:按列填
  • row dense
  • column dense

dense 的含义:

  • 浏览器会尝试把后面的较小项目回填到前面留下的空洞
  • 结果是视觉上更“紧凑”,但视觉顺序可能和 DOM 顺序不完全一致

9)间距:gaprow-gapcolumn-gap

.cards {
display: grid;
gap: 16px 24px;
}

含义:

  • 行间距 16px
  • 列间距 24px

优先级建议:

  • 新代码优先 gap
  • row-gap / column-gap 在需要单独控制时再拆开
  • 老写法 grid-gap 属于历史兼容写法,面试知道即可,不建议当首选答案

10)单元格内对齐:justify-itemsalign-itemsplace-items

这组属性控制的是:

网格项在自己的单元格/区域内部怎么摆

.board {
display: grid;
grid-template-columns: repeat(3, 120px);
justify-items: center;
align-items: center;
}
  • justify-items行内轴(inline axis) 对齐,默认通常可理解为横向
  • align-items块轴(block axis) 对齐,默认通常可理解为纵向
  • place-itemsalign-items / justify-items 的简写

常见值:

  • stretch(默认)
  • start
  • end
  • center

11)整个轨道组对齐:justify-contentalign-contentplace-content

这组属性控制的是:

整个网格轨道组在容器里怎么摆

只有当“网格总尺寸小于容器尺寸”时,这组属性效果才明显。

.panel {
display: grid;
width: 800px;
height: 500px;
grid-template-columns: repeat(2, 200px);
grid-template-rows: repeat(2, 100px);
justify-content: center;
align-content: space-between;
}
  • justify-content:控制整组轨道在行内轴上的分布
  • align-content:控制整组轨道在块轴上的分布
  • place-contentalign-content / justify-content 的简写

常见值:

  • start
  • end
  • center
  • stretch
  • space-between
  • space-around
  • space-evenly

12)grid 总简写

grid 是 Grid 的总简写,能同时覆盖:

  • grid-template-*
  • grid-auto-*
  • grid-auto-flow

面试知道它存在即可。工程里如果不是特别熟,拆开写更稳,因为 grid 可读性一般,写错也不容易排查。


三、子项属性(Item)完整清单

Grid 子项的核心问题只有一个:

它从哪条线开始,到哪条线结束;如果不显式指定,就按自动放置规则进入网格。

1)grid-column-start

.cardA {
grid-column-start: 2;
}

表示从第 2 条列线开始。

它可以写:

  • 数字:2
  • 负数:-1 表示最后一条线
  • 命名线:content-start
  • 关键字:auto
  • 跨度:span 2

2)grid-column-end

.cardA {
grid-column-start: 2;
grid-column-end: 4;
}

表示排到第 4 条列线结束。

3)grid-row-start

.cardB {
grid-row-start: 1;
}

4)grid-row-end

.cardB {
grid-row-start: 1;
grid-row-end: 3;
}

5)grid-column 简写

.main {
grid-column: 2 / 4;
}

等价于:

.main {
grid-column-start: 2;
grid-column-end: 4;
}

高频写法:

.header {
grid-column: 1 / -1;
}

.wideCard {
grid-column: span 2;
}
  • 1 / -1:从第一条线铺到最后一条线,常用于整行占满
  • span 2:横向跨 2 列

6)grid-row 简写

.sidebar {
grid-row: 1 / 3;
}

表示跨两行。

7)grid-area

grid-area 有两种用法。

第一种:引用命名区域。

.main {
grid-area: main;
}

第二种:四值简写。

.hero {
grid-area: 1 / 1 / 3 / 3;
}

它等价于:

  • grid-row-start: 1
  • grid-column-start: 1
  • grid-row-end: 3
  • grid-column-end: 3

面试里如果被追问,直接回答:

grid-area 既能写命名区域,也能写 row-start / column-start / row-end / column-end 的四值简写。

8)子项自对齐:justify-selfalign-selfplace-self

这组属性用于覆盖容器上的 justify-items / align-items,只对单个子项生效。

.badge {
justify-self: end;
align-self: start;
}
  • justify-self:单个项目在行内轴上的对齐
  • align-self:单个项目在块轴上的对齐
  • place-selfalign-self / justify-self 简写

9)order

Grid item 也支持 order

.promo {
order: -1;
}

作用:

  • 影响自动放置时的视觉顺序
  • 不改变 DOM 顺序
  • 无障碍、键盘导航、读屏语义不应该只靠它解决

四、Grid 里常用的单位、函数、关键字

这部分是面试高频,也是工程里最容易写错的地方。

1)fr

fr(fraction)表示 剩余空间的份额

grid-template-columns: 1fr 2fr;

含义:

  • 剩余空间按 1:2 分给两列

注意:

  • fr 分的是 剩余空间
  • 先扣掉固定宽度、内容约束、gap 等,再分配给 fr

2)repeat()

减少重复书写。

grid-template-columns: repeat(3, 1fr);

等价于:

grid-template-columns: 1fr 1fr 1fr;

还能配合自动轨道生成:

grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));

3)minmax(min, max)

给轨道设置上下界。

grid-template-columns: minmax(200px, 1fr) 2fr;

含义:

  • 第一列最小 200px
  • 空间足够时最多按 1fr 参与剩余空间分配

工程高频:

grid-template-columns: repeat(3, minmax(0, 1fr));

为什么常写 minmax(0, 1fr) 而不是直接 1fr

  • 因为 Grid item 可能受默认最小内容尺寸影响,不愿继续收缩
  • minmax(0, 1fr) 可以更明确地告诉浏览器:这列允许缩到 0
  • 如果内容仍然溢出,再配合子项 min-width: 0 更稳

4)fit-content()

表示:

轨道可以随内容增长,但不要超过给定上限。

grid-template-columns: 200px fit-content(320px) 1fr;

适合场景:

  • 某一列想“内容驱动”,但又不想无限变宽
  • 比如标签列、时间列、操作列

5)auto-fillauto-fit

这两个常和 repeat() + minmax() 一起用,做响应式卡片墙。

.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}

区别:

  • auto-fill:尽量 保留轨道槽位
  • auto-fit:尽量 折叠空轨道,让已有项目撑开

面试标准答法:

  • 两者都会自动生成尽可能多的轨道
  • auto-fill 更像“先把坑位占好”
  • auto-fit 更像“空坑位可以折叠,空间让给已有元素”

6)span

表示跨越多少个轨道。

.feature {
grid-column: span 2;
grid-row: span 2;
}

这比手写结束线在很多场景更直观。

7)命名网格线:[line-name]

.layout {
display: grid;
grid-template-columns:
[sidebar-start] 220px
[sidebar-end content-start] minmax(0, 1fr)
[content-end];
}

.main {
grid-column: content-start / content-end;
}

优点:

  • 语义比纯数字强
  • 大型布局比数线更不容易写错

8)subgrid

subgrid 是 Grid Level 2 的重要能力,常见于:

.itemList {
display: grid;
grid-template-columns: subgrid;
}

含义:

  • 子网格直接继承父网格对应轴的轨道定义
  • 适合需要和父布局严格对齐的复杂组件

面试里知道它的价值即可:

  • 父子网格对齐更自然
  • 不用重复维护相同的轨道尺寸

如果团队需要兼容较老浏览器,落地前仍要确认实际兼容范围。

9)非 Grid 专属,但经常一起出现的函数

这些不是 Grid 独有,但经常配合 Grid 使用:

  • min()
  • max()
  • clamp()

比如:

grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));

这种写法常用于小屏防止卡片最小宽度把容器撑爆。


五、面试里怎么系统地讲“所有属性”

如果面试官问“Grid 有哪些属性”,不要背流水账。推荐按下面这套答:

1)容器属性

  • 建显式网格:
    • grid-template-columns
    • grid-template-rows
    • grid-template-areas
    • grid-template
  • 控制隐式网格:
    • grid-auto-columns
    • grid-auto-rows
    • grid-auto-flow
  • 间距:
    • gap
    • row-gap
    • column-gap
  • 单元格内对齐:
    • justify-items
    • align-items
    • place-items
  • 整组轨道对齐:
    • justify-content
    • align-content
    • place-content
  • 总简写:
    • grid

2)子项属性

  • 放置位置:
    • grid-column-start
    • grid-column-end
    • grid-row-start
    • grid-row-end
    • grid-column
    • grid-row
    • grid-area
  • 单项对齐:
    • justify-self
    • align-self
    • place-self
  • 排序:
    • order

3)常用函数和值

  • fr
  • repeat()
  • minmax()
  • fit-content()
  • auto-fill
  • auto-fit
  • span
  • [line-name]
  • subgrid

六、典型场景(最小可用代码)

1)后台骨架布局

<div class="admin">
<header class="admin__header">header</header>
<aside class="admin__sidebar">sidebar</aside>
<main class="admin__main">main</main>
</div>
.admin {
display: grid;
min-height: 100vh;
grid-template-columns: 220px minmax(0, 1fr);
grid-template-rows: 64px 1fr;
grid-template-areas:
"header header"
"sidebar main";
}

.admin__header {
grid-area: header;
}

.admin__sidebar {
grid-area: sidebar;
}

.admin__main {
grid-area: main;
min-width: 0;
}

2)响应式卡片墙

.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 16px;
}

这是 Grid 最常见的工程写法之一。

3)局部元素跨列

.news {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 16px;
}

.news > .hero {
grid-column: 1 / -1;
}

hero 会整行占满,其余卡片按正常网格排。

4)回填空洞的卡片布局

.masonryLike {
display: grid;
grid-template-columns: repeat(4, 1fr);
grid-auto-rows: 80px;
grid-auto-flow: row dense;
gap: 12px;
}

.masonryLike > .tall {
grid-row: span 2;
}

注意:

  • 这是“类瀑布流”思路,不是真正意义上的 masonry
  • dense 可能改变视觉填充顺序,面试时可以顺手提这个坑

七、典型题 & 标准答法

Q1:Grid 和 Flex 有什么本质区别?

  • Flex 更适合一维布局,主要解决一行或一列里的分配与对齐
  • Grid 更适合二维布局,可以同时定义行和列
  • 工程里常见搭配是:页面骨架用 Grid,局部组件内部对齐用 Flex

Q2:justify-itemsjustify-content 有什么区别?

  • justify-items 控制的是 每个 grid item 在自己格子里怎么摆
  • justify-content 控制的是 整组网格轨道在容器里怎么摆
  • 一个是“格子内部对齐”,一个是“整张网格对齐”

Q3:auto-fitauto-fill 的区别?

  • 两者都常用于 repeat(..., minmax(...))
  • auto-fill 更倾向保留空轨道
  • auto-fit 更倾向折叠空轨道,让已有项目撑开

Q4:为什么 1fr 有时会撑爆,工程里常写 minmax(0, 1fr)

  • 因为 Grid item 默认会受最小内容尺寸约束
  • 直接写 1fr 时,某些长内容可能让轨道不愿继续缩
  • minmax(0, 1fr) 是在明确告诉浏览器:这列最小可以缩到 0
  • 真实项目里再配合子项 min-width: 0 更稳

Q5:grid-areagrid-template-areas 是什么关系?

  • grid-template-areas 是容器定义命名区域
  • grid-area 是子项把自己放进某个命名区域
  • grid-area 也可以单独写四值简写,不一定非要配合命名区域

Q6:Grid 项会自动换行吗?

  • 会,但更准确的说法不是“换行”,而是 按自动放置规则流入下一条隐式轨道
  • 如果你定义了多列,后续项目默认会继续排到下一行

Q7:什么时候不用 Grid?

  • 当问题本质只是单行分布、单列对齐、按钮组、导航、简单居中时,Flex 更直接
  • Grid 的优势在二维结构,不要为了“高级”而强行上 Grid

八、常见追问

1)命名区域和数字线编号,哪个更好?

  • 页面骨架、语义化布局:grid-template-areas 更直观
  • 复杂卡片拼排、跨列跨行:数字线 / 命名线更灵活
  • 大型工程里,两者可以混用

2)dense 值要不要常用?

  • 不建议默认就用
  • 它适合“视觉紧凑优先”的卡片流
  • 如果页面很依赖视觉顺序和 DOM 顺序一致,就要谨慎

3)subgrid 解决什么问题?

  • 解决父子网格轨道难对齐的问题
  • 让子组件能继承父组件的网格轨道
  • 适合复杂表单、卡片列表、信息面板

4)Grid 能完全替代圣杯布局、双飞翼布局吗?

  • 在现代工程里,大多数情况下可以直接替代
  • 但面试仍然会问圣杯/双飞翼,是为了考你对历史布局方案的理解

九、易错点 / 坑

  • grid-column: 2 / 4 理解成“第 2 列到第 4 列”,其实它说的是 第 2 条线到第 4 条线
  • justify-itemsjustify-content 混为一谈:一个管 项目在格子里,一个管 整张网格在容器里
  • 只会背 auto-fit / auto-fill 结论,不知道它们都是在 repeat() 里自动生成轨道。
  • 以为 Grid 的“自动换行”和 Flex 的 wrap 完全一样;更准确说法是 自动放置到后续隐式轨道
  • 直接写 1fr,结果长内容撑爆布局;常见修复是 minmax(0, 1fr) 或子项 min-width: 0
  • 乱用 orderdense 改视觉顺序,却忽略 DOM 顺序、读屏顺序和键盘导航顺序。
  • 区域名拼错、grid-template-areas 每行列数不一致、同名区域不是矩形,都会导致布局异常。

十、速记要点(可背诵)

  • Grid 是二维,Flex 是一维。
  • Grid 解题顺序:先画网格,再放元素,再谈对齐
  • 容器高频:grid-template-*grid-auto-*gapjustify/align/place-*
  • 子项高频:grid-columngrid-rowgrid-areajustify/align/place-self
  • 高频函数:repeat()minmax()fit-content()
  • 高频值:frauto-fitauto-fillspansubgrid
  • 整行铺满常写:grid-column: 1 / -1
  • 工程里最常见的一句:repeat(auto-fit, minmax(240px, 1fr))