想象你正在装修一套新房子。过去用 Flexbox 时,你只是在客厅里摆一排鞋柜:所有东西都沿着一条线排列,简单但很难同时管好整屋的横纵方向。CSS Grid 则不同,它让你先在一张图纸上画好整个户型的二维网格——横着有几面墙、竖着有几面墙、每个房间叫什么名字。等你把“客厅”“书房”“卫生间”标在图纸上,再把网页里的元素当作家具,一件件“搬”进对应的房间。这就是 Grid 布局:页面在水平和垂直两个方向上同时被安排,而“给房间贴名牌”的技术,就是网格区域命名。 更妙的是,这张户型图不是死的。你可以只定义区域名,让浏览器根据屏幕宽度自动增加或减少房间;可以留出走廊;还可以让 Flexbox 去处理房间内的一排小物件。CSS Grid 是二维布局的“总设计师”,Flexbox 是房间内“擅长摆一条线”的管家。掌握它,你就从“摆鞋柜”升级为“设计整屋”。
对 AI 从业者:AI 要生成可控、可维护的前端页面,必须理解 Grid 的二维骨架,尤其是“区域命名”这种接近自然语言的描述方式,能让模型像读户型图一样理解页面布局。
目录
可视化演示
展示CSS Grid的行列定义、区域命名与gap间距,通过交互控件切换不同网格模板,实时观察二维布局变化。
本节配有交互动效(进入视口后自动加载,约 3KB)。
CSS Grid区域命名 grid-template-areas定义区域 gap控制间距 display:grid
网格基础:先看懂户型图
拿到一套新房,设计师不会急着买家具,而是先在图纸上画横平竖直的参考线。CSS Grid 的第一步也是这样:在父元素上写 display: grid;,这个元素就变成了“网格容器”,它里面的直接子元素叫“网格项目”。网格容器里的横线和竖线叫“网格线”,两条相邻网格线之间的长条区域叫“轨道”,横轨和竖轨交叉出的最小格子叫“单元格”。
小区里每栋楼都有楼号,户型图上的参考线也同样重要。有了网格线和轨道,你才能准确说“把书架放在第 2 条竖线到第 3 条竖线之间”。Grid 和 Flexbox 最大的差别就在这里:Flex 只有一条“队伍”,而 Grid 同时管理横队和纵队。理解网格线,是后面所有定位的基础。
一个简单的网格容器需要定义列和行,否则所有项目会默认挤在一列里。无论横竖,线的数量都与轨道数有固定关系:
网格线只是骨架,真正让户型图实用的是“每面墙之间的距离”,这一步,就是下一节要学的行列定义。
- 网格线数户型图上所有横向或纵向参考线的总数。
- 轨道数两条相邻网格线之间的带状区域数量。
- 加一最外侧还有两条外边框线,所以线比轨道多一条。
行列定义:画出承重墙
参考线画好了,还得决定每面墙放在哪里、房间有多宽。CSS Grid 用 grid-template-columns 定义竖轨道的宽度,用 grid-template-rows 定义横轨道的高度。这就像在户型图上标注“客厅宽 4 米、卧室宽 3 米”,数值单位可以用像素、百分比,也可以用弹性单位 fr。
写 grid-template-columns: 100px 1fr 2fr; 时,第一列固定 100px,剩余空间先扣除列间距,再按 1 : 2 分给后两列。fr 是 Grid 特有的弹性单位,专门用于“按比例瓜分剩余空间”;repeat(3, 1fr) 则表示三间一样大的标准间,不用反复写同一个长度。这个分配逻辑可以写成:
墙画好了,接下来最关键的步骤,就是给这些房间贴上门牌号,让元素知道自己该住哪一间。
- W网格容器的总宽度,相当于整套房子的可用总面积。
- f_i当前列声明的
fr系数,比如1fr中系数是 1。 - 分母求和把所有列的弹性系数加起来,得到总份数。
- 扣除间距总宽度减去
n-1个列间距,剩下的才是真正能分给房间的面积。 - 按比例分配用当前系数除总份数,再乘剩余宽度,就得到该列宽度。
区域命名:给房间贴名牌
户型图上只有“格子”还不够,你还需要告诉别人“这里是厨房,那里是书房”。CSS Grid 的 grid-template-areas 就是用来画这张“字符地图”的:一行字符串代表网格的一行,每个名字代表一个单元格。比如:
写完地图后,子元素只要写 grid-area: main;,就会自动落到名为 main 的区域里。区域名必须组成一个完整矩形,用英文句号 . 表示“这个位置不放东西”。这种命名方式让布局像户型图一样一目了然,也方便后续在响应式设计中整体换图纸。一个命名区域在数学上可以看作一组连续的单元格:
给房间贴好名牌后,元素就能准确入住。但房间之间还需要留一点空隙,这就是接下来要讲的间距控制。
main 是行号从 r_s 到 r_e-1、列号从 c_s 到 c_e-1 的所有单元格的集合。- A_main名为 main 的网格区域,相当于户型图上画了斜线的那块房间。
- 二元组 (r, c)每个单元格的行号与列号,就像房间的“门牌坐标”。
- 起始行与列
r_s、c_s是区域左上角起始线。 - 结束行与列
r_e、c_e是区域右下角结束线,采用“含左不含右”规则。
grid-template-areas: "header header header" "sidebar main main" "footer footer footer";
间距控制:给房间留走廊
再紧凑的户型,也不会让两堵墙零距离贴在一起,总要留步行通道。CSS Grid 的 gap 就是这条走廊,专门控制网格轨道之间的间距。gap: 10px 20px; 表示行间距 10px、列间距 20px;也可以分开写成 row-gap 和 column-gap。
与 margin 不同,gap 是网格容器内部的“公共走廊”,不会算进某个房间的宽度里,也不会让容器被内容撑破。负的 gap 是不合法的,浏览器会忽略它。布局里一旦有多个轨道,计算总占用宽度时,必须把这些走廊也加进去:
走廊留好了,接下来要解决的是:如果家具没有被指定房间,它们该怎么自动摆放?
n-1 个间距,才是整套户型实际占用的总宽度。- 求和符号把每一列的房间宽度全部加起来。
- n网格的列数,也就是竖轨道数量。
- n-1列与列之间的走廊数量,比列数少一个。
- g单个列间距,由
column-gap定义。
自动排列:让机器人摆家具
不是每件家具都要你亲手指定房间。网格里没有写 grid-area 的项目,会自动按照顺序填进单元格,这个行为由 grid-auto-flow 控制。默认值是 row,像机器人先横着把第一排摆满,再换到第二排;设为 column 则会先竖着摆。
如果预先定义的行或列不够用,Grid 会自动创建额外轨道,这些轨道叫“隐式轨道”。它们就像户型图外临时搭出来的储物间。dense 关键字则让机器人更聪明:遇到空洞时,先拿后面的家具回头补上,让房间更紧凑,但视觉顺序可能不再完全等于源代码顺序。自动排列需要的总行数可以这样估计:
自动摆放解决了“塞得下”的问题,但手机和电脑屏幕大小不同,户型图还需要能变形。
- R需要的行数,包括自动生成的隐式行。
- N需要自动排列的网格项目总数。
- C每一行能放下的列轨道数。
- 向上取整如果除不尽,必须多开一行来放剩下的项目。
响应式设计:会变形的户型图
同一个家,在手机上是紧凑的一居室,在电脑上就是开阔的大平层。CSS Grid 的响应式设计,就是让户型图根据屏幕尺寸自动调整房间数量和大小。最常见的工具是媒体查询:在小屏幕上换一套 grid-template-areas,在大屏幕上再换一套。
另一个利器是 minmax(200px, 1fr):它规定轨道“最小不能小于 200px,最大可以按比例伸展”。配合 auto-fit 或 auto-fill,浏览器能自动决定一排放几列。auto-fill 倾向于尽量多放空轨道,auto-fit 倾向于把空轨道折叠后让项目变宽。auto-fill 能放下的列数大致可以这样估算:
户型图会变形之后,整个页面骨架就活了。但房间内部的细节,还需要另一个工种来配合。
w_min + g 的宽度,用容器总宽加一个间距去除,向下取整,就是最多能放下的列数。- N_列当前屏幕宽度下最多能容纳多少列。
- W容器可用总宽度。
- w_min每个轨道的最小宽度,比如
minmax(200px, 1fr)中的 200px。 - g列间距,需要加进每个轨道占用的总宽度里。
- 向下取整放不下最后一个完整轨道时,就不放,保证不会挤爆。
与Flex配合:两个工种分工
CSS Grid 是整屋设计师,负责“哪里放客厅、哪里放卧室”的二维大结构;Flexbox 是室内整理师,负责“书架上摆一排书、导航栏里排一排按钮”的一维小细节。两者不是对手,而是搭档。
在实际页面中,最常见的策略是“外层 Grid 拼骨架,内层 Flex 做排列”。比如整个后台页面用 grid-template-areas 分成顶栏、侧边栏、主内容区,而主内容区内部的一排操作按钮,再用 display: flex 来对齐。这样各司其职,代码清晰又灵活:
现在你已经有了完整的“装修工具箱”:先画户型图,再定义行与列,给房间命名,留出走廊,最后让 Grid 和 Flex 分工协作。下一次看到复杂页面,你就不再是“摆鞋柜”的新手,而是能画出整屋图纸的设计师了。
---
- 页面布局最终要实现的完整页面结构。
- GGrid 容器,用来规划整张户型图的区域。
- FFlex 容器,用来处理一个条带内的对齐和间距。
- 相加在 Grid 区域内部嵌套 Flex,两者组合使用。
AI 应用场景
场景一:AI 根据自然语言生成前端页面
阶段:生成式代码生成 / 前端智能体
解决的问题:传统方式手写响应式布局时,需要反复计算屏幕宽度、手动嵌套容器,遇到多端适配很容易“牵一发而动全身”。AI 助手如果能听懂“顶部通栏、左侧栏、主内容、底部通栏”,直接输出 grid-template-areas,就等于把户型图翻译成了 CSS 代码。
具体案例:开发一个在线页面试图工具,用户输入“我要三列卡片”,AI 自动生成 repeat(3, 1fr) 的网格;用户改成“中间主内容,右边广告栏”,AI 便生成带命名区域的 Grid 模板,前端工程师只需微调间距。
场景二:设计稿自动转代码
阶段:多模态识别 / 图像到代码
解决的问题:从 Figma 或 Sketch 截图转 HTML/CSS 时,传统模板很难还原复杂的二维区域关系。AI 目标检测把设计稿切分成矩形块后,可以映射为 grid-template-areas 的区域名,再翻译成行列模板,避免靠绝对定位硬拼。
具体案例:上传一张后台管理页面截图,AI 识别出 header、sidebar、main、footer 四个大块,输出标准 CSS Grid 布局代码;响应式断点也由 auto-fit 和 minmax 自动生成,人工只需要检查语义和颜色。
Python 演示
# -*- coding: utf-8 -*-# Parse grid-template-areas strings and generate CSS Grid codeimport re class GridAreaParser: def __init__(self, css_areas: str): self.css_areas = css_areas self.area_rows = [] self.area_map = {} self.row_count = 0 self.col_count = 0 self._parse() def _parse(self): lines = [ln.strip() for ln in self.css_areas.strip().splitlines() if ln.strip()] rows = [re.split(r"\s+", ln) for ln in lines] self.row_count = len(rows) self.col_count = max(len(r) for r in rows) for r, row in enumerate(rows): for c, name in enumerate(row): if name == ".": continue if name not in self.area_map: self.area_map[name] = [r, c, r + 1, c + 1] else: e = self.area_map[name] e[0] = min(e[0], r) e[1] = min(e[1], c) e[2] = max(e[2], r + 1) e[3] = max(e[3], c + 1) self.area_rows = rows def to_css(self): lines = [ "display: grid;", "grid-template-columns: repeat({}, 1fr);".format(self.col_count), "grid-template-rows: repeat({}, 1fr);".format(self.row_count), "grid-template-areas:", ] for row in self.area_rows: lines.append(" \"{}\";".format(" ".join(row))) for name in self.area_map: r1, c1, r2, c2 = self.area_map[name] lines.append(".{} {{ grid-area: {} / {} / {} / {}; }}".format(name, r1 + 1, c1 + 1, r2, c2)) return "\n".join(lines) + "\n" if __name__ == "__main__": layout = """ header header header sidebar main main footer footer footer """ parser = GridAreaParser(layout) print("rows:", parser.row_count, "cols:", parser.col_count) print(parser.to_css())
grid-template-areas 字符串解析成带行列坐标的 CSS Grid 代码,方便 AI 或工具自动生成前端布局。rows = [re.split(r"\s+", ln) for ln in lines]把户型图的每一行文字拆成单元格名字,变成二维数组。if name not in self.area_map:第一次遇到区域名时,记录它的起点和终点坐标。e[0] = min(e[0], r)不断向外扩展边界,让同名区域最终围成一个完整矩形。lines.append("grid-template-areas:")生成 CSS 里最像“字符地图”的属性。".{} {{ grid-area: {} / {} / {} / {}; }}".format(...)把每个区域名转换为四线定位,对应grid-row-start / grid-column-start / grid-row-end / grid-column-end。
常见误区
误区我只要给父元素加 `display: grid;`,里面的子元素就应该自动排成整齐的网格。
正解display: grid; 只是把父元素变成网格容器,像拿到了空白户型图。如果不写 grid-template-columns 和 grid-template-rows,Grid 只会按默认的自动排列规则处理,通常所有项目挤在一列里。真正的网格形状必须由列和行模板定义。
为何常见:很多教程直接展示“容器 + 列模板”的完整代码,初学者把列模板误当成了默认行为。
误区写上 `grid-area: main;` 就是在代码里创建一个叫 main 的大区域,并给它设置尺寸。
正解grid-area: main; 的含义是“把当前元素放进名为 main 的网格区域”,区域本身的大小由 grid-template-areas 和行列轨道决定。区域名是门牌号,不是房间面积。
为何常见:属性名里有 “area”,很容易让人联想到“划分区域”,但它本质上是一个“定位指令”。
误区元素之间距离 10px,用 `margin-right: 10px;` 加在每个项目上,不也一样吗?
正解margin 属于项目的外边距,会改变轨道内部的占用空间,搞不好还会让最后一个项目被挤到下一行。gap 是网格容器专门设置的“走廊”,不属于任何轨道,也不影响项目本身的宽度,是 Grid 推荐的做法。
为何常见:在 Flexbox 时代习惯用 margin 做间距,到了 Grid 会自然地延续旧习惯。
误区Flexbox 也能让元素一行排开,也能换行,那我直接用 Flexbox 不就行了?
正解Flexbox 本质是“一维排列”,要靠嵌套才能模拟二维结构;Grid 天然支持“行和列同时控制”,适合整页级的二维骨架。两者各有所长,正确姿势是“外 Grid 内 Flex”。
为何常见:简单页面用 Flexbox 看起来也能完成布局,直到遇到复杂后台或响应式大屏才会发现二维控制有多重要。
面试题
Q1. 在 CSS Grid 中,创建网格容器的属性是?
- A.
display: grid← 正确答案 - B.
display: flex - C.
position: grid - D.
display: block
答案:A。display: grid; 让元素成为网格容器,相当于拿到一张空白户型图。flex 创建的是弹性容器,position: grid 不存在,block 只是普通块级元素。
Q2. grid-template-columns: 100px 1fr 2fr; 中 1fr 2fr 的含义是?
- A.固定 1px 和 2px
- B.按 1:2 分剩余空间← 正确答案
- C.重复一至两次
- D.取值 1px 和 2px
答案:B。第一列固定 100px,剩下空间扣除间距后按 1:2 分给后两列。fr 是弹性单位,不是 1px 这样的固定长度,也不是重复次数。
Q3. 在 grid-template-areas 字符串中,英文句号 . 代表什么?
- A.对应位置留白← 正确答案
- B.代表一条网格线
- C.代表项目默认名
- D.占满全部空间
答案:A。.` 表示“这个单元格不放任何东西”,相当于户型图上的空地和储物间。它不是网格线,也不是项目的名字。
Q4. 下面哪种写法能生成三列等宽布局?
- A.
repeat(3, 1fr)← 正确答案 - B.
1fr repeat(3) - C.
grid-repeat(3) - D.
columns: 3 1fr
答案:A。repeat(3, 1fr) 表示三列等分剩余空间,是标准写法。其余选项语法错误或混淆了 columns 属性。
Q5. grid-template-areas 中,同一个命名区域必须是什么形状?
- A.任意形状多边形
- B.一个完整矩形← 正确答案
- C.只能是一条线
- D.必须是正方形
答案:B。CSS 规范要求命名区域必须组成单个完整矩形,L 形或圆形都无法被识别。就像户型图上,一个房间不能隔成两块不相连的碎片。
Q6. 以下哪些写法可以设置网格间距?
- A.
gap: 10px 20px← 正确答案 - B.
row-gap: 10px; column-gap: 20px← 正确答案 - C.
grid-gap: 20px← 正确答案 - D.
margin-gap: 10px
答案:ABC。gap 是标准简写,row-gap 和 column-gap 分开设置,grid-gap 是早期浏览器的兼容写法。margin-gap 不存在,间距不能靠 margin 冒充。
Q7. 关于 grid-auto-flow: dense,下列说法正确的是?
- A.能回填前面的空洞← 正确答案
- B.会改变 DOM 结构
- C.可能改变视觉顺序← 正确答案
- D.只能用于 row 方向
答案:AC。dense 允许后面较小的项目回头填充前面的空洞,所以视觉顺序可能与源码顺序不同,但 DOM 结构不会被修改。它不是只能在 row 方向使用。
Q8. grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) 在容器变宽时会怎样?
- A.固定为三列
- B.自动增多或减少← 正确答案
- C.永远只有一列
- D.列宽始终保持 200px
答案:B。auto-fit 会让浏览器根据可用宽度自动计算列数,minmax(200px, 1fr) 给每列设了下限和弹性上限。容器越宽,能放下的列就越多,列宽也会随之变大。
Q9. 关于 Grid 与 Flexbox 的分工,正确的是?
- A.Grid 适合二维骨架← 正确答案
- B.Flex 适合一行排列← 正确答案
- C.外层 Grid 内层 Flex← 正确答案
- D.两者不能同时出现
答案:ABC。Grid 同时控制行和列,适合搭整页骨架;Flexbox 擅长一条线上的对齐,适合导航栏、按钮组。实际项目中“外层 Grid 拼区域,内层 Flex 排细节”是最常见的组合。
Q10. 网格项目放进了尚未显式定义的轨道时,自动创建的轨道叫?
- A.隐式轨道← 正确答案
- B.显式轨道
- C.单元格轨道
- D.溢出轨道
答案:A。当项目超过 grid-template-columns/rows 定义的范围时,Grid 会自动生成额外轨道,也就是“隐式轨道”。它们像临时扩展出来的房间,尺寸由 grid-auto-columns 和 grid-auto-rows 控制。