首页
/ freeCodeCamp 课程挑战文件实战解析:用 hr 元素在卡片中创建水平分割线

freeCodeCamp 课程挑战文件实战解析:用 hr 元素在卡片中创建水平分割线

2026-09-06 12:18:17作者:蔡怀权

本文以 freeCodeCamp 开源课程库中的经典 HTML/CSS 挑战《Create a Horizontal Line Using the hr Element》为核心,完整解读挑战文档的字段与结构约定、种子代码(seed)与标准答案的构造方法,以及如何通过断言测试验证 <hr> 水平分割线的正确插入位置。读完后你将掌握该课程挑战文件的 Markdown 分节规范、void 元素 <hr> 的实际应用场景,以及前后挑战如何围绕同一张卡片递进演进的编写思路。

挑战在课程中的位置

该挑战文件位于英文课程目录下的 Applied Visual Design(应用视觉设计)模块:

applied-visual-design.jsonchallengeOrder 数组可以看到,该挑战(id 为 587d781b367417b2b2512abb)被安排在“Use the s Tag to Strikethrough Text”(删除线)之后、“Adjust the background-color Property of Text”(调整背景色)之前,模块的 helpCategory 标注为 HTML-CSS。整个模块由若干短小的挑战按序编排,共同围绕同一张“个人资料卡片”逐步搭建:前面的挑战为卡片的 h4 标题加入删除线文字,本挑战为标题与正文之间加一条水平线,后面的挑战再修改 h4 的背景色与内边距。这种“一张卡片逐步成型”的编排方式,是本模块最核心的教学设计。

挑战文档的结构规范

freeCodeCamp 的每个挑战都是一个带 YAML front matter 的 Markdown 文件,通过 # 一级标题分隔出若干固定分节。本挑战文件的完整骨架如下:

---
id: 587d781b367417b2b2512abb
title: Create a Horizontal Line Using the hr Element
challengeType: 0
videoUrl: '...'
forumTopicId: 301049
dashedName: create-a-horizontal-line-using-the-hr-element
---

# --description--    知识点讲解
# --instructions--   给学员的具体任务指令
# --hints--          分步提示,每条提示附对应测试断言
# --seed--
## --seed-contents-- 学员打开编辑器时的初始代码
# --solutions--      参考解答

front matter 各字段的作用:

字段 本挑战取值 说明
id 587d781b367417b2b2512abb 挑战唯一标识(MongoDB ObjectId),结构文件中的 challengeOrder 即按此 id 排序
title Create a Horizontal Line Using the hr Element 挑战标题
challengeType 0 挑战类型,用于区分经典编辑器挑战与测验等其他类型(类型定义见 packages/shared/src/config/challenge-types.ts
videoUrl 外部视频教程地址 可选的教学视频
forumTopicId 301049 关联的官方论坛主题编号
dashedName create-a-horizontal-line-using-the-hr-element 挑战的稳定 slug,用于生成 /learn/ 路由路径

挑战字段与分节的合法性由课程 schema 校验,相关校验逻辑位于 curriculum/schema/challenge-schema.js,其中使用 Joi 定义了 fileJoi(含 seedcontents 等代码文件字段)、prerequisitesJoi 等对象结构,课程构建时会依据 curriculum/package.json 中的测试流程对挑战文件做校验,保证每个挑战的结构完整、可被编辑器正确加载。

核心知识点:hr 是用于视觉分组的水平分割线

本挑战的 --description-- 分节给出了 <hr> 元素的标准定义:

你可以使用 hr 标签在其包含元素的宽度范围内绘制一条水平线。它可以用来表示话题的切换,或者在视觉上分隔不同组的内容。

结合 --instructions-- 分节的补充说明,需要掌握两个要点:

  1. 用途<hr> 表达的是“主题/内容分组的边界”这一语义,而不是单纯的装饰。在本挑战中,它恰好把卡片的标题区(h4)与介绍区(p)划分成两个视觉区块。
  2. void 元素:在 HTML 中 <hr> 是 void element(空元素),不需要单独的闭合标签,写 <hr> 即可,写成 <hr/> 也合法。这也是后文测试断言要同时兼容两种写法的原因。

种子代码(seed)解析

--seed-contents-- 分节中给出了学员打开编辑器时的完整初始代码。它是一张已具备样式的卡片:

<style>
  h4 {
    text-align: center;
    height: 25px;
  }
  p {
    text-align: justify;
  }
  .links {
    text-align: left;
    color: black;
  }
  .fullCard {
    width: 245px;
    border: 1px solid #ccc;
    border-radius: 5px;
    margin: 10px 5px;
    padding: 4px;
  }
  .cardContent {
    padding: 10px;
  }
  .cardText {
    margin-bottom: 30px;
  }
</style>
<div class="fullCard">
  <div class="cardContent">
    <div class="cardText">
      <h4><s>Google</s>Alphabet</h4>

      <p><em>Google was founded by Larry Page and Sergey Brin while they were <u>Ph.D. students</u> at <strong>Stanford University</strong>.</em></p>
    </div>
    <div class="cardLinks">
      <a href="https://en.wikipedia.org/wiki/Larry_Page" target="_blank" class="links">Larry Page</a><br><br>
      <a href="https://en.wikipedia.org/wiki/Sergey_Brin" target="_blank" class="links">Sergey Brin</a>
    </div>
  </div>
</div>

几个值得注意的衔接细节:

  • <h4> 中的 <s>Google</s>Alphabet 正是上一挑战587d781b367417b2b2512aba.md,“Use the s Tag to Strikethrough Text”)的作答结果被固化成了本挑战的 seed,直观体现了模块的递进关系;
  • 任务指令要求把 <hr> 加在“包含卡片标题的 h4 下方”,从 seed 结构看,也就是在 </h4><p> 之间(seed 中该行恰好留有一个空行作为提示位);
  • p 内的 emustrong 标签同样来自前序挑战(斜体、下划线、加粗)的作答,cardLinks 区则属于后续挑战(hover 状态、链接字号等)的改造对象。

标准答案与最小改动

--solutions-- 分节给出的参考解答与 seed 相比只有一行差异——在 h4p 之间插入 <hr>

<div class="fullCard">
  <div class="cardContent">
    <div class="cardText">
      <h4><s>Google</s>Alphabet</h4>
      <hr>
      <p><em>Google was founded by Larry Page and Sergey Brin while they were <u>Ph.D. students</u> at <strong>Stanford University</strong>.</em></p>
    </div>
    <div class="cardLinks">
      <a href="https://en.wikipedia.org/wiki/Larry_Page" target="_blank" class="links">Larry Page</a><br><br>
      <a href="https://en.wikipedia.org/wiki/Sergey_Brin" target="_blank" class="links">Sergey Brin</a>
    </div>
  </div>
</div>

样式部分(<style> 块)与 seed 完全一致,说明本挑战考察的只是语义元素的插入位置,不要求任何 CSS 改动。<hr> 作为块级元素,会自动横跨其包含元素 .cardText 的内容宽度,配合 .cardTextmargin-bottom: 30px,标题与正文之间形成清晰的视觉隔断。

测试断言解析:测试如何验证 hr 的正确性

--hints-- 分节中的每条提示都附带一条可执行的断言,它们也是平台判定挑战通过的最终依据:

断言一:页面中恰好存在一个 hr

assert.lengthOf(document.querySelectorAll('hr'),1);

通过 DOM API 统计 <hr> 数量,确认学员确实在标记中添加了水平线,且没有多余元素。

断言二:hr 必须位于标题与段落之间

assert.match(code,/<\/h4>\s*?<hr(>|\s*?\/>)\s*?<p>/gi);

这条正则直接匹配源代码文本,拆解如下:

片段 含义
<\/h4> 以标题结束标签为定位起点
\s*? 允许中间存在任意空白(懒匹配)
`<hr(> \s*?/>)`
\s*?<p> 紧随其后必须出现段落开始标签

gi 标志使其不区分大小写并可全局匹配。两条断言合起来即完整表达了任务要求:“在标记中添加一个 hr,且它必须夹在标题和段落之间”——与 --instructions-- 的文字描述一一对应。

小结:从一张挑战文件看课程编写范式

这篇挑战文件虽然内容简短,却完整覆盖了 freeCodeCamp 挑战编写的全部要素:front matter 元数据(id、dashedName、forumTopicId)、--description-- 中的知识点陈述、--instructions-- 的可执行任务、带断言的 --hints-- 分步提示、可直接运行的 --seed-contents--,以及最小 diff 的 --solutions--。再结合 applied-visual-design.json 的排序与前后挑战(删除线挑战背景色挑战)对同一张卡片的持续改造,可以看到该课程模块通过“小步递进、断言兜底”的方式,让 <hr> 这类基础 HTML 语义元素在具体项目语境中被反复巩固——这也是学习该仓库课程编写规范时值得参考的典型样例。

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

项目优选

收起
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.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
594
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
916
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
516
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388