freeCodeCamp 实战:用 CSS text-transform 属性将文本转为大写——Applied Visual Design 挑战解析
本文基于 freeCodeCamp 课程库中「Applied Visual Design」板块的挑战文档 587d781c367417b2b2512ac0.md 展开,讲解 CSS text-transform 属性的完整取值体系,并通过该挑战的原始代码、参考答案与测试断言,演示如何在卡片式页面中将 <h4> 标题渲染为大写,同时理解「视觉变换」与「修改 DOM 文本内容」的本质区别。
挑战在课程中的位置
该挑战属于 Responsive Web Design 认证下的 Applied Visual Design 板块。从 板块结构文件 可以看到,它是 challengeOrder 中的第 13 个挑战(元数据 id 为 587d781c367417b2b2512ac0,dashedName 为 use-the-text-transform-property-to-make-text-uppercase):
- 前一个挑战是「Decrease the Opacity of an Element」(降低元素不透明度);
- 后一个挑战是「Set the font-size for Multiple Heading Elements」(为多个标题设置字号)。
板块的归属关系可在 responsive-web-design.json 中确认:applied-visual-design 排在 basic-html-and-html5 与 basic-css 之后,是该认证的第 3 个板块——学习者先掌握 HTML 基础与 CSS 基础,再进入本板块做综合视觉设计练习。挑战元数据中 challengeType: 0 表示这是一个常规编码挑战,附有视频讲解与论坛讨论主题(forumTopicId: 301081)。
text-transform 属性取值全表
文档给出的核心知识是 text-transform 属性用于改变文本的外观(appearance),让页面文本保持一致的呈现风格,而无需改动 HTML 元素的实际文本内容。以下表格完整继承自原始文档,示例文本为 "Transform me":
| 值 | 结果 |
|---|---|
lowercase |
"transform me" |
uppercase |
"TRANSFORM ME" |
capitalize |
"Transform Me"(每个单词首字母大写) |
initial |
使用该属性的默认值 |
inherit |
继承父元素的 text-transform 值 |
none |
默认值:保持原始文本不变 |
需要注意两点语义区别:
none才是该属性的默认值,而initial的语义是「回到初始值」——对text-transform而言两者结果相同(都是none),但initial的作用是显式覆盖从父元素继承来的值;capitalize与uppercase不同:前者只把每个单词的首字母变大写,后者把所有字母都变大写。
任务要求与初始代码
挑战的指令(instructions)是:使用 text-transform 属性把 h4 的文本转换为大写。
初始代码(seed)是一个带阴影的卡片式布局,包含标题 <h4>Alphabet</h4>、一段关于 Google 创始人的段落和两个链接。为便于阅读,下文将链接的 href 统一替换为 #(原始文件 587d781c367417b2b2512ac0.md 中指向人物词条页面):
<style>
h4 {
text-align: center;
background-color: rgba(45, 45, 45, 0.1);
padding: 10px;
font-size: 27px;
}
p {
text-align: justify;
}
.links {
text-align: left;
color: black;
opacity: 0.7;
}
#thumbnail {
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23);
}
.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" id="thumbnail">
<div class="cardContent">
<div class="cardText">
<h4>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="#" target="_blank" class="links">Larry Page</a><br><br>
<a href="#" target="_blank" class="links">Sergey Brin</a>
</div>
</div>
</div>
这段 seed 代码本身就是一个「视觉设计」练习的延续:h4 已有居中对齐、半透明背景色、内边距和字号;#thumbnail 用两层 box-shadow 做出卡片浮起效果;.links 通过 opacity: 0.7 降低链接不透明度(即上一课的内容)。本课要做的,就是在 h4 规则里补上最后一块视觉细节——大写字号。
参考答案
官方 solutions 部分的修改只有一行:在 h4 选择器中追加 text-transform: uppercase;。
<style>
h4 {
text-align: center;
background-color: rgba(45, 45, 45, 0.1);
padding: 10px;
font-size: 27px;
text-transform: uppercase;
}
/* 其余规则(p、.links、#thumbnail、.fullCard、.cardContent、.cardText)与 seed 完全一致 */
</style>
<div class="fullCard" id="thumbnail">
<div class="cardContent">
<div class="cardText">
<h4>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="#" target="_blank" class="links">Larry Page</a><br><br>
<a href="#" target="_blank" class="links">Sergey Brin</a>
</div>
</div>
</div>
渲染后 h4 显示为 "ALPHABET",但注意 HTML 源码里的文本节点仍然是 Alphabet——这正是 text-transform 的设计意图:只改渲染结果,不改数据。
测试断言如何验证「只改外观,不改内容」
原始文档的 hints 部分包含两组自动化断言,它们精确界定了通过本挑战的两个条件。
条件一:h4 的计算样式必须是 uppercase。
const h4Element = document.querySelector('h4')
const h4Style = window.getComputedStyle(h4Element);
assert.equal(h4Style?.textTransform, 'uppercase');
这里使用的是 window.getComputedStyle,它返回元素的计算样式(camelCase 键名,如 textTransform)。这意味着测试检查的是浏览器解析样式表后的最终生效值,而不是你在 HTML 上写了什么属性——即使值来自 inherit 从父级继承,只要计算结果是 uppercase 就能通过。
条件二:h4 的原始文本不能真的被改成大写。
assert.notEqual(
document.querySelector('h4')?.textContent,
document.querySelector('h4')?.textContent?.toUpperCase()
);
这条断言要求 textContent 与它自身的大写形式不相等,即文本节点里必须还保留着小写字母(Alphabet 而非 ALPHABET)。它从反面拦截了「直接把 HTML 里的字母敲成大写」这种错误解法:那样虽然视觉正确,但违背了「用 CSS 属性完成变换」的挑战目标,也破坏了内容与表现分离的原则。
两条断言合起来恰好完整描述了 text-transform 的语义边界:样式层负责呈现(getComputedStyle 可见),数据层保持原样(textContent 不变)。这一点对可访问性和国际化都有实际意义——屏幕阅读器、复制粘贴、以及后续多语言翻译读取的都是原始文本,而不是视觉上的大写形态。
该属性在 freeCodeCamp 平台自身代码中的应用
text-transform 并非课程里的孤立知识点,freeCodeCamp 自己的客户端代码就大量使用它。从源码结构看,至少以下组件样式表包含该属性:
- profile.css:个人页面组件;
- searchbar-base.css:搜索栏基础样式;
- donation.css:捐赠组件;
- landing.css:落地页组件。
这说明「用 CSS 变换文字大小写来控制视觉层级」是真实生产代码中的常规手法,与本课程挑战所练习的场景一致。
小结
通过这一挑战,可以掌握三件事:
text-transform的六个取值(lowercase/uppercase/capitalize/initial/inherit/none)及默认值为none的语义;- 在既有卡片样式(
text-align、background-color、box-shadow等)基础上用一行声明完成大写标题的视觉调整; - 用
getComputedStyle与textContent双断言验证「样式生效」与「内容未改」两个正交条件,理解 CSS 表现层与 HTML 数据层的分离。
挑战原文(含完整 seed、solutions 与测试代码)见 curriculum/challenges/english/blocks/applied-visual-design/587d781c367417b2b2512ac0.md,板块完整挑战顺序见 applied-visual-design.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 StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00