freeCodeCamp Basic CSS 挑战精讲:用 Hex 十六进制代码表示颜色(Use Hex Code for Specific Colors)
本篇指南基于 freeCodeCamp 课程仓库中的挑战文件 use-hex-code-for-specific-colors,完整讲解 CSS 中十六进制(hex)颜色代码的数学原理、表示规则与实操步骤,并结合仓库内的挑战校验逻辑、种子代码(seed)与标准答案(solutions),说明这道基础 CSS 题是如何被自动判分的。读完后你将掌握:hex 数与十进制数的对应关系、RRGGBB 六位颜色码的读写方法、在 <style> 中替换颜色写法,以及如何读懂课程仓库中挑战的测试断言与正则校验。
挑战在课程结构中的位置
该挑战属于 basic-css 区块,其区块元数据定义在 basic-css.json 中。从 challengeOrder 数组可以确认,"Use Hex Code for Specific Colors"(id 为 bad87fee1348bd9aedf08726)紧接在 "Override All Other Styles by using Important" 之后,排在颜色知识序列的起点,其后依次是:
- "Use Hex Code to Mix Colors"(用 hex 混合颜色)
- "Use Abbreviated Hex Code"(使用简写 hex)
- "Use RGB values to Color Elements"(使用 RGB 值)
也就是说,本篇文档是整条"颜色表示法"学习链的第一环:先学会标准 6 位 hex 码,再学混色、简写和 RGB 等价写法。
挑战文件自身是带 YAML frontmatter 的 Markdown,frontmatter 中各字段含义如下:
| 字段 | 本文件取值 | 作用 |
|---|---|---|
id |
bad87fee1348bd9aedf08726 |
课程系统中该挑战的唯一标识,也是文件名 |
title |
Use Hex Code for Specific Colors |
挑战标题 |
challengeType |
0 |
挑战类型编号。在 challenge-types.ts 中,0 对应 HTML 类型,UI 分类映射为 'classic'(经典单文件 HTML/CSS 题) |
videoUrl |
一段外部视频教程地址 | 配套讲解视频(frontmatter 中为 scrimba 链接) |
forumTopicId |
18350 |
配套社区论坛帖子编号 |
dashedName |
use-hex-code-for-specific-colors |
URL 化的 slug,用于课程页面路由 |
核心知识一:十六进制数(Hex)是什么
文档首先解释了"颜色表示法"背后的数学基础。我们日常使用的**十进制(decimal)**是 base 10,每一位用 0~9 共 10 个符号表示。**十六进制(hexadecimal)**是 base 16,使用 16 个不同符号:
0~9表示数值 0~9(与十进制相同);A、B、C、D、E、F分别表示数值 10~15。
因此单个十六进制位的取值范围是 0 到 F,共 16 种可能值。这一进位规则正是后面"每两位 hex 恰好能表示一个 0~255 的通道分量"的关键(16 × 16 = 256)。
核心知识二:CSS 中用 6 位 hex 表示颜色
在 CSS 中,颜色用 6 个十六进制位表示,每两位分别对应红色(R)、绿色(G)、蓝色(B)三个分量,即 #RRGGBB 结构:
- 红色分量 = 第 1~2 位;
- 绿色分量 = 第 3~4 位;
- 蓝色分量 = 第 5~6 位。
文档给出的示例是纯黑:#000000 三个通道分量均为 0,是色域的最低值:
body {
color: #000000;
}
这套表示法建立在 RGB 颜色模型之上:每种颜色的"亮度"由红、绿、蓝三个分量的强度叠加决定。每个分量取 0~255 共 256 个级别,三个分量组合出 256³ ≈ 1677 万种颜色,这也是为什么 6 位 hex(每位 16 种取值,共 16⁶)与 RGB 三位十进制写法能覆盖完全相同的颜色范围——后文 RGB 挑战中也正是这样说明两者的等价性的。
实战:完成 "Use Hex Code for Specific Colors" 挑战
任务要求(instructions)
将
body元素background-color中的颜色单词black替换为它的 hex 代码表示#000000。
初始代码(seed)
挑战加载到编辑器中的初始代码如下(来自文档 --seed-- 部分):
<style>
body {
background-color: black;
}
</style>
标准答案(solutions)
只需把颜色单词换成 hex 写法:
<style>
body {
background-color: #000000;
}
</style>
background-color: black 与 background-color: #000000 在浏览器中渲染结果完全一致,本挑战的目的正是让学习者建立"颜色名 ↔ hex 码"的映射习惯——这是后续混色(如橙色 #FFA500)与简写(如 #F00)的基础。
挑战如何判分:双重校验机制
文档 --hints-- 部分包含两条 JS 断言,揭示了该仓库对挑战答案的两层验证策略:渲染结果校验 + 源码模式校验。
第一层:检查实际渲染出的计算样式
const body = document.querySelector('body');
const backgroundColor = window.getComputedStyle(body)['background-color'];
assert.strictEqual(backgroundColor, 'rgb(0, 0, 0)');
window.getComputedStyle 读取元素实际生效的样式。注意断言的期望值是 'rgb(0, 0, 0)' 而不是 '#000000'——因为浏览器会把 hex 颜色在计算样式中规范化(normalize)为 rgb() 形式。这解释了为什么"写 #000000"与"写 black"在这一层无法区分:两者渲染出来都是 rgb(0, 0, 0)。
第二层:用正则约束源码写法
assert.match(code, /body\s*{(([\s\S]*;\s*?)|\s*?)background.*\s*:\s*?#000(000)?((\s*})|(;[\s\S]*?}))/gi);
这条正则直接匹配用户提交的 HTML 源码(变量 code),拆解其各部分:
body\s*{ ... }:锚定body选择器块,块内允许存在其他声明([\s\S]*;部分可匹配前导的其他分号结尾声明);background.*\s*:\s*?:匹配background-color等以background开头的属性赋值;#000(000)?:核心约束——颜色值可以是#000也可以是#000000,即 3 位简写与 6 位全写都通过;((\s*})|(;[\s\S]*?})):允许该声明后还有别的声明;/gi标志:不区分大小写(#000与#000000均可)、全局搜索。
两层断言合起来的含义是:渲染结果必须是黑色,且源码中必须显式使用 hex 字面量(#000 或 #000000),不允许只写颜色名 black。这种"计算样式 + 源码正则"的组合是该仓库经典 HTML 挑战的典型判分模式(同区块的 RGB 挑战、简写 hex 挑战 都采用相同结构)。
挑战文件在仓库中的结构约定
该文件整体遵循 freeCodeCamp 挑战 Markdown 的分节约定,用 # --section-- 标题划分区块:
| 分节 | 本文件内容 | 用途 |
|---|---|---|
# --description-- |
十六进制原理、hex 颜色说明与示例代码 | 挑战页正文(学习材料) |
# --instructions-- |
"把 black 换成 #000000" |
任务说明 |
# --hints-- |
两条 JS 断言 | 判分测试与提示 |
# --seed-- / ## --seed-contents-- |
初始 HTML(background-color: black) |
编辑器初始代码 |
# --solutions-- |
参考答案(background-color: #000000) |
标准解与自动测试基线 |
这些字段会被课程 schema 校验。在 challenge-schema.js 中,fileJoi 定义了每个代码文件对象必须包含的键,包括 seed(第 29 行)与 contents 等;而 solutions 被校验为"由文件数组组成的非空数组"(第 365 行):
solutions: Joi.array().items(Joi.array().items(fileJoi).min(1)),
即每个挑战至少要有一个方案,每个方案至少包含一个可编辑文件——本文件的 --solutions-- 代码块正是填充这里的来源。
同系列挑战延伸:从 hex 到混色、简写与 RGB
读完本篇后,按 basic-css.json 中的顺序,接下来的三个挑战会依次加深同一主题:
- Use Hex Code to Mix Colors:讲解三个纯色通道如何按比例混合出 1600 多万年色。要点是
0表示该通道完全缺失(无亮度),F表示最大亮度。例如橙色是"满红 + 部分绿 + 无蓝",即#FFA500(FF=255 满红,A5=165 中绿,00=无蓝)。该挑战要求把red/green/dodgerblue/orange四个颜色名替换为#FF0000、#00FF00、#1E90FF、#FFA500。 - Use Abbreviated Hex Code:当 6 位 hex 的每一位两两相同时(
#FF0000→ 每通道都是FF),可压缩为 3 位:红色#F00、绿色#0F0、青色#0FF、紫红色#F0F。文档说明浏览器会将#FF0000与#F00解释为完全相同的颜色,简写形式把可选颜色数降到约 4000 种(16³)。 - Use RGB values to Color Elements:介绍等价物
rgb(0, 0, 0)(黑)与rgb(255, 255, 255)(白)。由于"hex 每两位 = 16 × 16 = 256 个值",RGB 的 0~255 与 hex 的两位完全等值,该挑战要求把background-color: #F00换成rgb(0, 0, 0)。
四种写法(颜色名、6 位 hex、3 位 hex、rgb())的对应关系可以整理为:
| 颜色 | 颜色名 | 6 位 hex | 3 位 hex | RGB |
|---|---|---|---|---|
| 黑 | black |
#000000 |
#000 |
rgb(0, 0, 0) |
| 红 | red |
#FF0000 |
#F00 |
rgb(255, 0, 0) |
| 绿 | green |
#00FF00 |
#0F0 |
rgb(0, 255, 0) |
| 青 | cyan |
#00FFFF |
#0FF |
rgb(0, 255, 255) |
| 橙 | orange |
#FFA500 |
—(不可简写) | rgb(255, 165, 0) |
注意橙色 #FFA500 每通道两位并不相同(FF/A5/00),因此没有等价的 3 位简写——这正是简写规则"每位必须两两相同"的直接推论。
本地复现与验证
想脱离课程平台练习这道题,可以保存一个静态 HTML 文件,例如 hex-color.html:
<!DOCTYPE html>
<html>
<head>
<style>
body {
background-color: #000000;
}
</style>
</head>
<body>
<h1 style="color: white;">Hex color demo</h1>
</body>
</html>
用任意静态服务器或直接双击打开后,可在浏览器控制台执行挑战同款的第一层断言逻辑来验证:
const body = document.querySelector('body');
window.getComputedStyle(body)['background-color'];
// 期望输出: 'rgb(0, 0, 0)'
第二层正则断言则用于检查源码文本,把上面 assert.match 中的正则替换为你保存的文件内容即可自查。
小结
- CSS 颜色可以用 6 位十六进制
#RRGGBB表示,每个通道两位 hex 对应 0~255 的亮度(16² = 256 个级别),与 RGB 十进制表示一一对应; - 十六进制的
A~F代表 10~15,单个 hex 位有 16 种取值,6 位共 16⁶ ≈ 1677 万种颜色; - 本挑战要求把
body的background-color: black改写为background-color: #000000,答案与判分逻辑完整保存在 挑战源文件 的--solutions--与--hints--分节中; - 判分采用"计算样式断言(
getComputedStyle期望rgb(0, 0, 0))+ 源码正则(#000(000)?)"双重校验,确保结果正确且写法符合要求; - 后续 混色、简写 hex、RGB 三个挑战在同一 区块顺序 中逐步展开完整的颜色表示法知识链。
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 StartedRust0625
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