首页
/ freeCodeCamp Basic CSS 挑战解析:Adjust the Margin of an Element —— 从入门理解到自动化验证

freeCodeCamp Basic CSS 挑战解析:Adjust the Margin of an Element —— 从入门理解到自动化验证

2026-09-06 18:14:20作者:郦嵘贵Just

本文围绕 freeCodeCamp 开源仓库中 Basic CSS 课程区块(basic-css block)的一道入门挑战 Adjust the Margin of an Element 展开,系统讲解 CSS margin 属性的作用机制与盒模型中的定位,并逐行剖析该挑战 Markdown 文档(frontmatter、描述、seed 初始代码、hints 自动化测试与官方 solution)在仓库中的真实结构与实现。读完本文,你将既能学会如何正确调整元素的 margin,也能理解 freeCodeCamp 的课程挑战文件是如何通过 window.getComputedStyle 等断言被自动校验的。

课程中该挑战的定位

该挑战的源文件位于 curriculum/challenges/english/blocks/basic-css/bad87fee1348bd9aedf08822.md,是全英文官方课程(freeCodeCamp 课程体系采用"challenges/english 为主干、其余语言经 curriculum/i18n-curriculum 翻译"的组织方式)中 Basic CSS 区块的一环。

curriculum/structure/blocks/basic-css.json 中的 challengeOrder(第 70~73 行)可以看到该挑战被精确编排在如下序列中:

挑战 主题
bad88fee1348bd9aedf08825 Adjust the Padding of an Element
bad87fee1348bd9aedf08822 Adjust the Margin of an Element
bad87fee1348bd9aedf08823 Add a Negative Margin to an Element
bad87fee1348bd9aedf08824 Add Different Margins to Each Side of an Element
bad87fee1348bd9afdf08726 Use Clockwise Notation to Specify the Margin of an Element

也就是说,学习者先学会调整元素内部的 padding,再学会调整元素外部的 margin,随后依次接触负外边距、逐边设置以及顺时针简写,构成一条完整的盒模型间距学习链。本文所处的这一题,正是其中承接 padding、开启 margin 认知的关键一课。

挑战文档的 frontmatter:挑战即数据

freeCodeCamp 的每个挑战本质上是一个带 frontmatter 的 Markdown 文档。本文件的 YAML 头如下:

---
id: bad87fee1348bd9aedf08822
title: Adjust the Margin of an Element
challengeType: 0
videoUrl: 'https://scrimba.com/c/cVJarHW'
forumTopicId: 16654
dashedName: adjust-the-margin-of-an-element
---

各字段的意义分别为:

  • id:挑战的唯一标识(ObjectId 格式),后续构建学习地图、存取进度都依赖它;
  • title:页面标题,同时会被 curriculum/structure/blocks/basic-css.jsonchallengeOrder 引用;
  • challengeType:挑战类型编号,0 代表经典的 HTML/CSS 网页类挑战;
  • videoUrl:可选的视频讲解链接(本挑战挂接了 Scrimba 讲解视频);
  • forumTopicId:关联论坛讨论帖 ID;
  • dashedName:URL 友好的英文短名。

从仓库的 curriculum/schema/challenge-schema.js 可以看到这些字段并非随意书写,而是受到 Joi 模式的强校验:id 要求为合法的 ObjectId 且必填(第 36 行),title 必填(第 37 行),challengeType 必须是 0~33 之间的数字(第 180 行),dashedName 需匹配 slug 正则(第 182 行),videoUrl 允许为空字符串(第 241 行)。也就是说,这类 .md 文档与结构 JSON、schema 校验代码共同构成了可机器验证的课程数据源。

核心概念:margin 控制的是什么空间

挑战的 # --description-- 部分给出了对 margin 最精炼的定义:

An element's margin controls the amount of space between an element's border and surrounding elements.

翻译过来就是:margin(外边距)控制的是元素 border(边框)与周围元素之间的距离。它是 CSS 标准盒模型(content → padding → border → margin,由内向外)中最外层的一环:

  1. content——内容区;
  2. padding——边框与内容之间的内边距;
  3. border——元素的边框;
  4. margin——边框之外、用于隔开相邻元素的外边距。

因此,一个元素设置 margin 后,并不会改变它自身的"占地"内容,而是通过扩大与邻近元素的间距,在视觉上产生更小的存在感。这正是题目描述中强调的:外层黄色盒子中嵌套着红、蓝两个盒子,红色盒子的 margin 更大,看起来就更"小"、与黄色盒子边缘更疏远。

任务:让蓝盒子的 margin 追上红盒子

挑战指令非常直接:

Change the margin of the blue box to match that of the red box.

也就是把 .blue-boxmargin 调整到与 .red-box 一致(20px)。理解这一步的关键是 seed 中提供的 HTML/CSS 结构:

<style>
  .injected-text {
    margin-bottom: -25px;
    text-align: center;
  }

  .box {
    border-style: solid;
    border-color: black;
    border-width: 5px;
    text-align: center;
  }

  .yellow-box {
    background-color: yellow;
    padding: 10px;
  }

  .red-box {
    background-color: crimson;
    color: #fff;
    padding: 20px;
    margin: 20px;
  }

  .blue-box {
    background-color: blue;
    color: #fff;
    padding: 20px;
    margin: 10px;
  }
</style>
<h5 class="injected-text">margin</h5>

<div class="box yellow-box">
  <h5 class="box red-box">padding</h5>
  <h5 class="box blue-box">padding</h5>
</div>

这段演示代码值得逐层拆解:

  • .yellow-box 同时应用了 border-style/border-color/border-width(来自 .box)与黄色背景、padding: 10px,扮演"容器"角色;
  • .red-box.blue-box 是两个嵌套在黄色容器内的子元素,各自有 padding: 20px 以撑大自身、白色文字以便区分底色;
  • 两者唯一的关键差异就在 margin:红盒子 margin: 20px,蓝盒子 margin: 10px

所以当学习者把蓝盒子的 margin10px 改为 20px 后,蓝色盒子的边框会离其所在容器的内边缘更远,视觉大小(外围所占空间)与红盒子保持一致。这里的 margin: 20px 是四向简写,等价于同时为 margin-top/right/bottom/left 设置 20px

值得一提的细节是 .injected-text { margin-bottom: -25px; }:它利用负外边距把说明文字 "margin" 向上吸附,这与下一道挑战 Add a Negative Margin to an Element 形成呼应。

Hints:自动化断言如何检验 margin

与许多只靠"肉眼对比"的教程不同,freeCodeCamp 的挑战自带可执行的测试(# --hints--),本挑战只有一条断言:

const blueBox = document.querySelector('.blue-box');
const marginTop = window.getComputedStyle(blueBox)['margin-top'];
assert.strictEqual(marginTop, '20px');

其校验思路是:

  1. document.querySelector('.blue-box') 选中蓝盒子;
  2. 通过 window.getComputedStyle(blueBox) 读取浏览器最终计算后的样式表;
  3. 断言计算后的 margin-top 恰好等于 '20px'

getComputedStyle 取的是级联与计算完成后的实际值,因此即便学习者采用 margin: 20px 20px;margin-top: 20px 或四条分写等不同写法,只要最终计算出的上边距为 20px 就能通过——这体现了课程"以结果正确性为准"的自动判题哲学。可以在 curriculum/challenges/english/blocks/basic-css/bad87fed1348bd9aede07836.md 等相邻挑战中看到同类 window.getComputedStyle 断言在颜色、背景等属性校验上的复用,例如校验 background-color 时直接断言计算值为 rgb(192, 192, 192)

需要说明的是,getComputedStyle 返回的值会将颜色归一化为 rgb(...) 形式、长度归一到以 px 为后缀的字符串,这也是断言里使用 strictEqual(marginTop, '20px')(而非数字 20)的原因。

官方解法(Solution)

仓库在每个挑战的 # --solutions-- 段给出了标准答案。对本挑战而言,唯一改动就是把 .blue-box 的 margin 对齐红盒子:

<style>
  .injected-text {
    margin-bottom: -25px;
    text-align: center;
  }

  .box {
    border-style: solid;
    border-color: black;
    border-width: 5px;
    text-align: center;
  }

  .yellow-box {
    background-color: yellow;
    padding: 10px;
  }

  .red-box {
    background-color: crimson;
    color: #fff;
    padding: 20px;
    margin: 20px;
  }

  .blue-box {
    background-color: blue;
    color: #fff;
    padding: 20px;
    margin: 20px;
  }
</style>
<h5 class="injected-text">margin</h5>

<div class="box yellow-box">
  <h5 class="box red-box">padding</h5>
  <h5 class="box blue-box">padding</h5>
</div>

对比 seed,唯一差异为 .blue-boxmargin10px 变为 20px。这也再次印证:margin 是元素边框与周边元素间的距离,调大它不会改变元素内容与 padding,只会让元素在布局中"退后",看起来更小、间距更大。

margin 的进阶形态:逐边与简写

掌握四边等值的 margin: 20px 写法后,同一区块接下来的挑战帮助学习者覆盖两种进阶语法:

配合稍早的 Adjust the Padding of an Element,学习者至此就能完整地驾驭盒模型的 paddingmargin:前者向内"撑大",后者向外"推开"。

结语

通过本挑战可以同时收获两层认识:其一,作为 CSS 学习者,理解了 margin 在盒模型中的位置——它是元素边框外侧与相邻元素之间那段可调节的空白,调节它会直接影响元素在页面布局中的间距与观感;其二,作为开源仓库的阅读者,看到了 freeCodeCamp 如何把一道题拆解为描述、指令、可执行断言与参考答案四段式结构,并用 Joi schema 校验 frontmatter、用 challengeOrder 决定授课顺序。如果想进一步验证相关约定,可继续阅读 curriculum/structure/blocks/basic-css.json(课程编排)、curriculum/schema/challenge-schema.js(挑战文件字段校验)以及 curriculum/challenges/english/blocks/basic-css/ 目录下围绕 margin/padding 的其他挑战源文件。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390