4.5 Grid网格布局


Grid 网格布局

本节摘要:如果说 Flexbox 解决"一行里怎么排",Grid 解决的就是"整个页面怎么排"。CSS Grid 是第一个专为二维布局设计的 CSS 模块——同时定义行和列,用 fr 单位分配空间,用区域命名"画"出布局图,用 auto-fit 免媒体查询实现响应式卡片墙。复杂页面框架从此变成一段声明式代码。

学习目标

完成本节后,你将能够:使用 grid-template-columnsgrid-template-rows 定义网格结构;使用 grid-columngrid-row 控制项目的跨行跨列;使用 grid-template-areas 用"画图"的方式定义布局;理解 fr 单位、repeat()auto-fit 的配合,写出无媒体查询的响应式网格。

核心概念:容器、轨道、项目

和 Flexbox 类似,Grid 也有容器和项目的区分。display: grid 把一个元素变成 Grid 容器,它的直接子元素自动成为 Grid 项目。

Grid 容器的核心是网格轨道——水平方向的叫行轨道,垂直方向的叫列轨道。轨道的边界形成网格线,项目通过网格线编号来定位(从 1 开始数,列线从左到右,行线从上到下;还有负数编号,-1 永远代表最后一条线)。

.container { display: grid; grid-template-columns: 200px 1fr 200px; /* 三列:左栏固定,中间弹性,右栏固定 */ grid-template-rows: 60px 1fr 40px; /* 三行:头部 60px,中间弹性,底部 40px */ gap: 16px; /* 行列间距 */ }

经典的三行三列页面网格骨架

对比一下 Flexbox:同样的三行三列用 Flex 得嵌三层容器(外层 column、中间行 row、每行再排),而 Grid 一层容器直接把行列全声明完——当布局同时有行和列两个维度时,Grid 的代码量呈数量级下降。这就是"一维用 Flex、二维用 Grid"这条经验的来源。

fr 单位和 repeat 函数

fr(fraction,分数)是 Grid 引入的长度单位,表示剩余空间的一个等份。它是 Grid 布局中最常用的单位。

/* 三列等宽 */ grid-template-columns: 1fr 1fr 1fr; /* 用 repeat() 简化 */ grid-template-columns: repeat(3, 1fr); /* 混合单位:固定 + 弹性 */ grid-template-columns: 250px 1fr 250px; /* 侧栏 2 倍宽于另一侧栏 */ grid-template-columns: 2fr 1fr;

fr 与百分比的关键差别:fr 分配的是扣除固定轨道和间距之后的剩余空间,百分比则是相对容器总量各算各的——混用固定值时,fr 不需要你心算"100% 减去 250px 再减几个 gap"。

repeat() 函数可以重复轨道定义,还能配合 auto-fillauto-fit 实现自动填充:

/* 自动填充:每列至少 200px,能放多少放多少 */ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* auto-fit 类似,但项目不足时空轨道会折叠 */ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));

这行代码值得单独讲透,它是"免媒体查询响应式"的核心:minmax(200px, 1fr) 规定每列"最小 200px、最大均分剩余";auto-fit 让浏览器数一数容器宽度能容下几列,容器变宽列变多、变窄列变少。整段布局从手机到宽屏全自动适配,一行媒体查询都不用写。

项目定位:grid-column 和 grid-row

Grid 项目默认按照源码顺序依次放入网格单元格。你可以用 grid-columngrid-row 显式指定项目的位置和跨度。

/* 项目从第 1 条列线开始,到第 3 条列线结束(跨 2 列) */ .header { grid-column: 1 / 3; } /* 项目从第 2 条行线开始,跨 2 行 */ .sidebar { grid-row: 2 / 4; } /* 简写:起始线 / 跨度 */ .featured { grid-column: 1 / span 2; /* 从第 1 列线开始,跨 2 列 */ grid-row: 1 / span 2; /* 从第 1 行线开始,跨 2 行 */ } /* 负数线:从数第二列跨到最后一列 */ .wide { grid-column: 2 / -1; }

线编号思维初看别扭,但它是处理"不规则布局"的瑞士军刀:杂志式排版里第一篇文章占两行两列、其余单格,全靠 span 完成。动手做个小实验:三列网格里给第一个项目写 grid-column: 1 / -1,它横跨整行成了通栏头条,后面的项目自动流进剩余格子——显式定位和自动流动可以混用。

grid-template-areas:画出来的布局

grid-template-areas 是 Grid 中最直观的布局方式——用字符串"画"出网格的布局图,每个区域起个名字,代码即图纸。

.page { display: grid; grid-template-columns: 250px 1fr; grid-template-rows: 60px 1fr 40px; grid-template-areas: "header header" "sidebar content" "footer footer"; min-height: 100vh; } .header { grid-area: header; } .sidebar { grid-area: sidebar; } .content { grid-area: content; } .footer { grid-area: footer; }

每个字符串代表一行,空格分隔的单词代表列。同一个单词占据多格表示项目横跨。用 . 表示空白的单元格。区域命名规则只有两条:矩形区域必须是完整的矩形(不能拼出 L 形);每个名字可以用一次或多次。

响应式改造是这套语法的杀手锏——移动端改单列时,只需要"重画"区域图,元素本身的 grid-area 一行不用动:

@media (max-width: 768px) { .page { grid-template-columns: 1fr; grid-template-areas: "header" "content" "sidebar" "footer"; } }

桌面端侧栏在左、内容在右;移动端内容升到第二位、侧栏沉到第三位——纯粹的"换图纸",零件原封不动。这种把"布局结构"和"内容元素"彻底解耦的写法,是 Grid 带来的工程质变。

对齐与间距

Grid 容器可以用和 Flexbox 相同的属性来控制对齐,而且多了一层——Flex 管的是"一行/列项目",Grid 可以同时管"单元格内"和"整个网格"两级:

.container { display: grid; gap: 16px; /* 行列间距 */ /* row-gap: 16px; 只设行间距 */ /* column-gap: 24px; 只设列间距 */ justify-items: center; /* 每个项目在自己单元格内水平居中 */ align-items: center; /* 每个项目在自己单元格内垂直居中 */ /* 整体对齐:网格在容器里的位置(容器比网格大时才有意义) */ justify-content: center; align-content: center; }
属性 控制对象 典型用途
gap 轨道间距 卡片之间的间隔
justify-items 项目在单元格内的水平位置 单元格内容居中
align-items 项目在单元格内的垂直位置 图标网格垂直居中
justify-content 网格整体的水平位置 网格居中
align-content 网格整体的垂直位置 稀疏网格垂直居中

记忆技巧:带 -items 的管格子里的内容,不带 -items 的管整张网格——多出来的这层正是"二维"带来的。

实战:完成个人主页的整页框架

把全教程的个人主页项目收尾,用 Grid 搭出完整框架,内部再嵌 Flex——两种布局的正统配合:

/* 整页框架:Grid 负责大结构 */ .site { display: grid; grid-template-columns: 220px 1fr; grid-template-rows: 64px 1fr auto; grid-template-areas: "header header" "sidebar main" "footer footer"; min-height: 100vh; } .site-header { grid-area: header; display: flex; align-items: center; justify-content: space-between; padding: 0 24px; background: #1565C0; color: #fff; } .site-sidebar { grid-area: sidebar; padding: 24px; background: #F5F5F5; } .site-main { grid-area: main; padding: 24px; } .site-footer { grid-area: footer; padding: 16px; text-align: center; color: #757575; } /* 主内容区:响应式卡片墙,Grid 管格子 */ .work-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px; } /* 单张卡片内部:Flex 管一行布局 */ .work-card { display: flex; flex-direction: column; gap: 8px; border: 1px solid #E0E0E0; border-radius: 8px; padding: 16px; } .work-card .actions { margin-top: auto; /* Flex 技巧:把按钮行推到卡片底部 */ display: flex; gap: 8px; }

三层结构各司其职:.site 用区域命名画出整页图纸;.work-gridauto-fit 让作品卡片从手机一格、平板两格、桌面三格全自动变化;每张卡片内部用 Flex 纵向排列,margin-top: auto 把操作按钮钉在卡片底端——不等高的卡片也整整齐齐。拖动浏览器窗口宽度逐档观察变化,你会看到"框架 Grid、内容 Flex、细节定位"的完整分工。

再补一个全宽技巧:

/* 内容区限宽居中,但某张横幅要冲破限宽铺满全行 */ .site { grid-template-columns: 1fr min(800px, 90%) 1fr; } .site > * { grid-column: 2; } /* 常规内容放中列 */ .breakout { grid-column: 1 / -1; } /* 横幅从第一条线到最后一条线 */

左右两列 1fr 是留白,中间列限宽,"普通内容居中、个别元素全宽"的经典杂志版式三行搞定。

💡 动手建议:用 grid-template-areas 把你最喜欢的网站首页"翻译"成区域图——先在纸上画格子命名,再翻成 CSS。然后打开该网站的开发者工具对照它的实际做法,你会发现很多网站的骨架与你画的图大同小异。

⚠️ Grid 项目只能是其直接父容器的子元素。如果你想让一个嵌套很深的元素参与 Grid 布局,要么把它移到容器的直接子级,要么使用 display: subgrid(较新的特性,让子网格继承父网格的轨道定义)。另外,项目设置 grid-area 名字后忘了在容器里定义对应的区域模板,项目会跑到隐式网格里"失踪"——排查"元素不见了"时先查名字拼写。

常见疑问解答

问:auto-fillauto-fit 有什么区别? 两者都会"按容器宽度数格子",差别在项目不足时:auto-fill 保留空轨道占位,网格总轨道数不变;auto-fit 把空轨道折叠为零宽,现有项目会把腾出的空间分掉。卡片数量多的场景两者观感一致,项目少(比如只有一两张卡)时 auto-fit 会让它们拉伸变宽——想要"宁可留白也不许卡片太胖"就用 auto-fill,反之用 auto-fit

问:为什么我的项目没进我指定的格子? 检查两件事:定位语法是"起始线/结束线",只写一个数字时它会被理解为起始线且跨度为一——grid-column: 2 不是"从第二条线到末尾",要写 2 / -1;用了 grid-area 名字时,容器模板里必须真的定义了这个名字,拼错名字的项目会被塞进隐式网格的末尾,看起来像"消失了"。

问:Grid 能做不规则布局吗? 能,两条路:网格线加 span——给个别项目声明跨行跨列,其余自动流动填充,适合杂志式版面;区域命名画图——把大块布局直接画出来,适合页面骨架。注意区域命名要求每个名字占据完整矩形,拼不出 L 形;L 形需求请回到网格线方案。

问:Grid 和 Flex 怎么在一个页面里分工? 经验法则:先问"这是框架还是组件"。页面骨架、内容与侧栏的关系、卡片墙的整体分布——Grid;一行工具栏、卡片内部图文排列、按钮组——Flex。两层嵌套(Grid 外 Flex 内)是最常见的组合,反过来(Flex 外 Grid 内)在"每个弹性项目内部是规则网格"时也成立。判断标准始终是需求的维度,而不是技术的流行度。

布局声明式的胜利

回头看一眼本章开头的总纲——"Grid 管大框架,Flexbox 管组件内部"——现在这句话已经有了完整的支撑。更重要的是体会 Grid 代表的范式变化:过去描述一个布局,靠的是"过程"(先浮动、再清除、再补边距,一步一步逼近效果);Grid 描述布局靠的是"结构声明"(几行几列、谁在哪块、间距多少,一张图纸说完)。声明式的代码像图纸,可读、可改、可对照——把设计稿翻译成区域图,几乎是一比一的誊写。

这种"图纸感"还改变了协作方式。设计师看 grid-template-areas 的字符串基本能直接读懂页面结构,评审布局代码不再是程序员的独角戏;产品讨论"把侧栏从左移到右",改动只是交换两个词的位置。当布局代码的形态接近布局本身,沟通成本就塌缩了。

学习建议也随之更新:练 Grid 最好的方式不是刷属性文档,而是"翻译练习"——找喜欢的页面,画出它的行列结构,命名区域,写成模板,再用几占位色块验证。翻译十个页面后,任何设计稿在你眼里都会自动分解成行、列与区域——这种"网格之眼"一旦长成,就不会再退化。

同样留一份"需求到属性"的速查:整页框架用区域命名画图;等宽多列用 repeat(数字, 1fr);响应式卡片墙用 repeat(auto-fit, minmax(最小宽, 1fr))gap;个别项目通栏用 grid-column: 1 / -1;不规则跨格用起始线加 span;格子内容对齐用 justify-itemsalign-items,整张网格在容器里居中用 justify-contentalign-content。这七条加上"外 Grid 内 Flex"的组合意识,就是你上岗开局的全套装备——遇到新需求时先在这七条里找映射,找不到再查文档,学习曲线会平缓得多。同样推荐反向练习:随机把两条组合起来(比如通栏项目加自适应列),先在纸上画出预期版式,再写代码验证,几轮之后"网格之眼"就看什么都自带坐标系了。

本节要点回顾

  • 二维声明grid-template-columnsrows 一次定义行列,复杂框架一层容器搞定,Flex 需要的嵌套被声明取代。
  • fr 与 minmaxfr 分配扣除固定值后的剩余空间;minmax(最小, 1fr)auto-fit 实现免媒体查询的响应式网格。
  • 两种定位:网格线编号加 span 适合不规则排版;grid-template-areas 画图纸,响应式改图不改件。
  • 两级对齐-items 管单元格内,整网格用 justify-content/align-content
  • 黄金组合:Grid 搭框架、Flex 管组件内部、细节交给定位;margin-top: auto 把元素钉到弹性容器的另一端。
  • 全宽技巧:三列 1fr 内容 1frgrid-column: 1 / -1,限宽版式里穿插全宽元素。

至此布局篇收官。最后一篇总结将把四章知识串成一张全景图,并给出通往响应式、动画、设计系统的进阶路线。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U