freeCodeCamp 课程源码解析:用嵌套 CSS Grid 构建「网格中网格」布局
本篇以 freeCodeCamp 响应式设计课程中「Create Grids within Grids(在网格中创建网格)」这一练习(challenge)为蓝本,完整继承其种子代码、操作步骤与验证断言,并结合同一课程块(block)中的前置练习与课程结构文件,讲清 CSS Grid 嵌套布局的工作原理:把任意网格项(grid item)再声明为 grid 容器,即可得到层级化、可独立控制子项排布的多层网格。读完后,你将掌握嵌套网格的触发条件(只作用于直接子元素)、display: grid 与 grid-template-columns 的配合用法,以及如何用 fr、auto 等网格单位混合定义列宽。
核心概念:嵌套网格只影响直接子元素
freeCodeCamp 课程中该练习的原始描述(见 Create Grids within Grids)点出了嵌套网格的本质:
Turning an element into a grid only affects the behavior of its direct descendants. So by turning a direct descendant into a grid, you have a grid within a grid.
把任一元素设为网格容器后,CSS Grid 的排版规则只会作用于它的直接子元素,更深层的后代不受影响。反之,当你把网格容器的某个直接子元素(grid item)也设置 display: grid 时,该元素就成了一个独立的内层网格容器,它与自己的子元素构成一套完整的新网格——这就是「网格中的网格」。
这一特性对应到页面结构上非常直观:外层 .container 负责页面骨架(广告栏、页头、内容区、页脚),而内容区 .item3 内部的段落排版由它自己的网格规则决定,两层布局互不干扰、各自独立调整。
课程定位:css-grid 块中的最后一道练习
从课程结构文件 css-grid.json 可以看到,css-grid 块按 challengeOrder 顺序编排了 22 个练习,从 Create Your First CSS Grid 开始,依次覆盖列、行、间隙、对齐、grid-template-areas 区域模板、repeat/minmax/auto-fill 等函数,最终落在本练习「Create Grids within Grids」(id: 5a94fe8569fb03452672e464)。该块隶属于 responsive-web-design.json 超级块,即 freeCodeCamp 响应式设计认证课程的一部分。理解这一编排,有助于把握本练习为何是整块的收尾:前面各练习的知识点(网格单位、区域模板、grid-area 定位)在这里全部汇聚,用于构建一个真实感更强的多列页面骨架。
完整种子代码:一个带区域模板的外层网格
练习的种子代码(seed)定义了一个 3 行 2 列的页面骨架网格。完整代码如下,其中 .item3 内部预留了注释标记的改动区域:
<style>
.container {
font-size: 1.5em;
min-height: 300px;
width: 100%;
background: LightGray;
display: grid;
grid-template-columns: auto 1fr;
grid-template-rows: auto 1fr auto;
grid-gap: 10px;
grid-template-areas:
'advert header'
'advert content'
'advert footer';
}
.item1 {
background: LightSkyBlue;
grid-area: header;
}
.item2 {
background: LightSalmon;
grid-area: advert;
}
.item3 {
background: PaleTurquoise;
grid-area: content;
/* Only change code below this line */
/* Only change code above this line */
}
.item4 {
background: lightpink;
grid-area: footer;
}
.itemOne {
background: PaleGreen;
}
.itemTwo {
background: BlanchedAlmond;
}
</style>
<div class="container">
<div class="item1">header</div>
<div class="item2">advert</div>
<div class="item3">
<div class="itemOne">paragraph1</div>
<div class="itemTwo">paragraph2</div>
</div>
<div class="item4">footer</div>
</div>
这段种子代码中蕴含了三个前置练习的知识点,建议对照原文件阅读:
- 区域模板
grid-template-areas:字符串模板'advert header' / 'advert content' / 'advert footer'把网格划成header、advert、content、footer四个命名区域,其中advert跨三行竖贯左侧。每个单词代表一个单元格,每对引号代表一行——这与前置练习 Divide the Grid Into an Area Template 的讲解一致。 grid-area定位网格项:.item1到.item4各自通过grid-area: header等声明进入对应命名区域,见前置练习 Place Items in Grid Areas Using the grid-area Property。- 网格单位
fr与auto:grid-template-columns: auto 1fr表示第一列宽随内容自适应(auto),剩余空间全部分给第二列(1fr);grid-template-rows: auto 1fr auto同理定义了三行。这些单位的语义(fr为可用空间的一份、auto由内容撑开、%相对容器)在 Use CSS Grid units to Change the Size of Columns and Rows 中有完整说明。
值得注意的是,.itemOne 和 .itemTwo 两个子元素目前只有背景色,没有任何网格规则——它们是内层网格的「占位项」,等待 .item3 成为网格容器后才被排版。
任务:把 item3 变成 auto 1fr 的两列网格
课程给出的原始指令是:
Turn the element with the
item3class into a grid with two columns with a width ofautoand1frusingdisplayandgrid-template-columns.
即使用 display 和 grid-template-columns 两个属性,把 .item3 变成一个两列网格:第一列宽 auto(随子项内容宽度),第二列宽 1fr(占满内容区剩余空间)。标准答案只需在 .item3 的改动区域内补充两行声明:
.item3 {
grid-template-columns: auto 1fr;
display: grid;
}
两行声明的分工可以拆开看:
display: grid是触发嵌套的关键。没有这一行,.item3只是外层网格的一个普通项,内部的.itemOne、.itemTwo会以普通的块级流纵向堆叠。grid-template-columns: auto 1fr定义内层网格的列模板,让两个段落子项各占一列:第一列被paragraph1的文字宽度撑开,第二列吃掉剩余宽度。由于声明只写在.item3上,外层.container的三行两列布局完全不受影响——这正是「网格只作用于直接子元素」这一规则的实际体现。
验证方式:正则断言检查声明是否写入正确的选择器
该练习属于 challengeType: 0(自由代码编辑型)的练习类型,freeCodeCamp 的课程数据格式用一组正则断言来验证学员代码是否满足要求。本练习的两条断言(引自原文档 --hints-- 部分)分别检查:
assert.match(
code,
/.item3\s*?{[\s\S]*grid-template-columns\s*?:\s*?auto\s*?1fr\s*?;[\s\S]*}/gi
);
assert.match(code, /.item3\s*?{[\s\S]*display\s*?:\s*?grid\s*?;[\s\S]*}/gi);
从正则结构可以看出课程对答案的判定标准:两条声明必须出现在 .item3 选择器块内部(正则从 .item3 { 开始,在其闭花括号范围内匹配),且 grid-template-columns 的值严格为 auto 1fr、display 的值严格为 grid。这种「选择器 + 块内声明」的匹配方式,也间接提醒了嵌套网格的常见错误:把 display: grid 误写到外层 .container 或子项 .itemOne 上是通不过验证的,因为网格声明必须落在作为嵌套起点的那个直接子元素上。
延伸:从嵌套网格到响应式布局
嵌套网格解决的是「局部排版自治」问题,而 freeCodeCamp 的 css-grid 块中另一个练习 Use Media Queries to Create Responsive Layouts 则处理容器尺寸变化时的整体重排。二者结合正是本练习骨架的典型应用场景:外层 auto 1fr 让广告栏窄、内容区宽;内层 auto 1fr 让段落自适应文字;当视口变窄时,可以通过媒体查询改写内层的 grid-template-columns(例如改成单列 1fr),而不必触碰外层骨架。这种「每层网格各自定义列模板、各自响应断点」的分层思路,是 CSS Grid 构建复杂页面(如课程中出现的杂志版式、报纸版式布局练习,见 css-grid 超级块结构 中的 workshop-magazine 与 lab-newspaper-layout)的基础模式。
小结
- 嵌套条件:元素成为网格容器后,布局规则仅作用于其直接子元素;把某个 grid item 再声明为
display: grid,即得到网格中网格。 - 本题解法:在
.item3中加display: grid;与grid-template-columns: auto 1fr;,使其内部paragraph1、paragraph2两子项形成两列内层网格。 - 单位语义:
auto由内容决定宽度,1fr占满剩余可用空间,两者混合使用是「固定语义列 + 弹性内容列」的常见搭配。 - 验证机制:课程用正则断言确认两条声明写在
.item3选择器块内,体现了声明作用域对嵌套网格正确性的关键性。
完整原始题目、种子代码与参考答案见 curriculum/challenges/english/blocks/css-grid/5a94fe8569fb03452672e464.md,练习顺序见 curriculum/structure/blocks/css-grid.json。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00