freeCodeCamp HTML 表单课程精讲:用 checked 属性让单选按钮与复选框默认选中
本指南围绕 freeCodeCamp 响应式网页设计(Responsive Web Design)认证下 "Basic HTML and HTML5" 模块的第 24 个挑战(标题为 Check Radio Buttons and Checkboxes by Default)展开,系统讲解 HTML 表单中 checked 属性的作用、写法、运行时语义,并结合该挑战的题目、自动化测试(hints)与官方参考实现进行逐行剖析。读完你不仅能独立完成这道闯关练习,还能理解"HTML 标记中的默认选中"与"浏览器中的实际选中状态"之间的关系,以及 checked、value、name 等属性在表单数据提交中的分工。
挑战在课程体系中的定位
该挑战文件位于 curriculum/challenges/english/blocks/basic-html-and-html5/bad87fee1348bd9aedd08835.md,元数据(frontmatter)表明它属于 challengeType: 0(基础代码闯关型挑战),并挂载了配套的视频讲解与论坛主题链接。
从模块的编排文件 curriculum/structure/blocks/basic-html-and-html5.json 可以看到,它处在一组层层递进的表单课程末尾部分,其直接前驱是:
- Create a Set of Radio Buttons(bad87fee1348bd9aedf08834.md)——掌握
name相同即构成单选组、选项互斥的原理; - Create a Set of Checkboxes(bad87fee1348bd9aedf08835.md)——掌握多选控件的基本写法;
- Use the value attribute with Radio Buttons and Checkboxes(5c6c06847491271903d37cfd.md)——掌握提交表单时数据如何以
name=value形式上报。
本挑战是这个链条的收尾:此前课程只要求"能选中",本课则要求"默认就处于选中状态"。同模块后续的 Nest Many Elements within a Single div Element、Declare the Doctype of an HTML Document 等则转向结构语义与文档骨架,说明本挑战是 CatPhotoApp 表单部分最后一块交互拼图。
核心知识点:checked 布尔属性
课程说明给出的一句话定义是本课的题眼:
你可以通过
checked属性让一个复选框(checkbox)或单选按钮(radio button)在页面加载时默认处于选中状态。
实现方式极为简单:只需在对应的 input 元素内部加上单词 checked,例如:
<input type="radio" name="test-name" checked>
需要说明的是,checked 属于 HTML 的布尔属性(boolean attribute)之一。它的判定规则是"只看属性是否存在,不看值",因此:
<input type="radio" checked> <!-- 合法,默认选中 -->
<input type="radio" checked="checked"> <!-- 合法,默认选中 -->
<input type="radio" checked=""> <!-- 合法,默认选中 -->
<input type="radio"> <!-- 未选中 -->
<input type="checkbox" checked> <!-- 复选框同样适用 -->
在绝大多数情况下,按课程示例直接书写裸属性 checked 即可,这也是最能体现布尔属性本意的写法。
单选按钮组与复选框的默认状态差异
虽然 checked 对 type="radio" 与 type="checkbox" 都生效,但它们的互斥语义截然不同,这正是本挑战设计成"单选按钮和复选框各设置一个默认选中"的原因:
- 单选按钮(radio):同一组(
name相同)中任何时候最多只能有一个处于选中状态。用户点击任意一个,同组其他项自动取消选中。 - 复选框(checkbox):同一组内每个复选框相互独立,可以同时勾选多个,也可以全部不勾选。
与之对应,HTML 规范规定:如果同一单选组中有多个元素在标记里写了 checked,浏览器解析后只会让其中某一个处于选中(实践中通常表现为树序中最后一个),因此不要通过"写多个 checked"试图实现多选——单选组天然不允许这种状态。而在一个组里给多个输入写 checked 也不会在提交时生效为多值。反观复选框没有此限制,想默认勾选几个就写几个。
任务实操:让 CatPhotoApp 表单单选与复选默认选中
挑战的指令(instructions)非常明确:
将你表单中的第一个单选按钮和第一个复选框都设置为默认选中。
--seed-- 段给出了完整起始代码。为了便于对照行号,其表单部分结构如下(完整代码见 bad87fee1348bd9aedd08835.md 的 seed 段):
<h2>CatPhotoApp</h2>
<main>
<p>Click here to view more <a href="#">cat photos</a>.</p>
<a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a>
<p>Things cats love:</p>
<ul>
<li>catnip</li>
<li>laser pointers</li>
<li>lasagna</li>
</ul>
<p>Top 3 things cats hate:</p>
<ol>
<li>flea treatment</li>
<li>thunder</li>
<li>other cats</li>
</ol>
<form action="https://www.freecatphotoapp.com/submit-cat-photo">
<label for="indoor"><input id="indoor" type="radio" name="indoor-outdoor" value="indoor"> Indoor</label>
<label for="outdoor"><input id="outdoor" type="radio" name="indoor-outdoor" value="outdoor"> Outdoor</label><br>
<label for="loving"><input id="loving" type="checkbox" name="personality" value="loving"> Loving</label>
<label for="lazy"><input id="lazy" type="checkbox" name="personality" value="lazy"> Lazy</label>
<label for="energetic"><input id="energetic" type="checkbox" name="personality" value="energetic"> Energetic</label><br>
<input type="text" placeholder="cat photo URL" required>
<button type="submit">Submit</button>
</form>
</main>
动手步骤
- 找到表单中的第一组单选按钮。
indoor-outdoor组按文档顺序排列,第一个即id="indoor"、标签文本为Indoor的那个<input>,在它的标签内补上checked。 - 找到复选框组。
personality组中的第一个是id="loving"、标签文本为Loving的<input>,同样补上checked。 - 保留其余控件(
outdoor、lazy、energetic、文本输入框、提交按钮)原封不动,尤其是两个 label 的显示文本必须保持不变,否则会触发后面的校验失败。
两个关键点:单选组内只能默认选中一个(indoor);复选框仅把组内第一个设为默认勾选,其余留空,以演示"复选框可部分默认选中"这一行为。
官方参考实现解析
--solutions-- 段给出了经过验证的完整答案,与 seed 的唯一差异正是两处 checked(对照 bad87fee1348bd9aedd08835.md):
<h2>CatPhotoApp</h2>
<main>
<p>Click here to view more <a href="#">cat photos</a>.</p>
<a href="#"><img src="https://cdn.freecodecamp.org/curriculum/cat-photo-app/relaxing-cat.jpg" alt="A cute orange cat lying on its back."></a>
<p>Things cats love:</p>
<ul>
<li>catnip</li>
<li>laser pointers</li>
<li>lasagna</li>
</ul>
<p>Top 3 things cats hate:</p>
<ol>
<li>flea treatment</li>
<li>thunder</li>
<li>other cats</li>
</ol>
<form action="https://www.freecatphotoapp.com/submit-cat-photo">
<label for="indoor"><input id="indoor" type="radio" name="indoor-outdoor" value="indoor" checked> Indoor</label>
<label for="outdoor"><input id="outdoor" type="radio" name="indoor-outdoor" value="outdoor"> Outdoor</label><br>
<label for="loving"><input id="loving" type="checkbox" name="personality" value="loving" checked> Loving</label>
<label for="lazy"><input id="lazy" type="checkbox" name="personality" value="lazy"> Lazy</label>
<label for="energetic"><input id="energetic" type="checkbox" name="personality" value="energetic"> Energetic</label><br>
<input type="text" placeholder="cat photo URL" required>
<button type="submit">Submit</button>
</form>
</main>
可以看到:indoor 单选与 loving 复选框各加了一个 checked,结构零改动,这也印证了"默认选中只关乎属性本身,与元素顺序、嵌套层级无关"。
自动化校验(hints)逐条拆解
freeCodeCamp 的这类挑战会在你的代码于 iframe 中渲染后执行一段浏览器端 JavaScript 断言(hints),全部通过才算完成。本挑战共四条(见文档 hints 段):
assert.isTrue(document.querySelector('input[type="radio"]').checked);
- 作用:断言页面第一个
type="radio"输入(即indoor)的 DOM 属性.checked为true。 - 注意
document.querySelector只返回文档中第一个匹配元素,因此该断言天然对应"第一个单选按钮"。 - 校验的是运行时 DOM 的
checked属性(property) 而非静态源码字符串——也就是说,只有当你把checked写在正确的<input>上,浏览器解析后.checked才会为真。
assert.isTrue(document.querySelector('input[type="checkbox"]').checked);
- 同上,断言第一个复选框(
loving)默认选中。checkbox 与 radio 的选择器前缀区分了控件类型,验证你两种类型都处理到了。
assert.equal(document.querySelector('label[for="indoor"]')?.innerText?.trim(), 'Indoor');
assert.equal(document.querySelector('label[for="loving"]')?.innerText?.trim(), 'Loving');
- 这两条用于保护题目语义不被破坏:
Indoor与Loving两个标签文本必须保持原样。代码中的可选链?.表示若找不到对应 label 直接判失败,.trim()去除首尾空白后再做严格相等比较。 - 它们的存在意味着解题时不能通过改写选项文字来"作弊",只能靠
checked达成目的。
这些测试的定义方式也对应着仓库中对挑战文件结构的校验规则:在 curriculum/schema/challenge-schema.js 中,tests 字段被定义为由 { text, testString } 组成的数组,testString 即上述 JS 断言字符串,而 hints 段中的每条提示正好一一映射为该挑战运行时执行的测试用例。
常见失败情形自查
| 现象 | 可能原因 |
|---|---|
| 第一条 radio 断言失败 | checked 写在了 outdoor 而非 indoor 上;或两个单选都写了 checked 导致浏览器仅保留其中一个 |
| 第一条 checkbox 断言失败 | checked 写在了 lazy/energetic 上;或根本没有添加该属性 |
| label 文本断言失败 | 修改了 Indoor/Loving 的显示文字,或在标签中混入了多余空白以外的字符 |
| 语法层报错 | 把 checked 写成了 checked="true" 以外的非法组合或写在了 </input> 后——实际上 input 是空元素,属性只能写在其开始标签内 |
与 value、name 的关系:默认选中之后,表单提交什么?
前面的课程已经强调过 value 的作用,这里需要把三者的分工彻底厘清,否则很容易把"默认选中"和"提交内容"混淆:
name:定义控件的数据键。同一单选组共用同一个name,提交时只上报被选中的那一项。value:定义控件的数据值。如 5c6c06847491271903d37cfd.md 所强调的:若省略value,表单数据会退化为无意义的on;设置value="indoor"后,用户选中 indoor 并提交,服务器收到的就是indoor-outdoor=indoor。checked:只决定初始呈现的选中状态,本身不参与数据提交。
也就是说,本挑战中的 indoor 单选同时具备三个属性,它们各司其职:
<input id="indoor" type="radio" name="indoor-outdoor" value="indoor" checked>
name="indoor-outdoor"决定它属于哪个单选组;value="indoor"决定被选中后以indoor-outdoor=indoor提交;checked决定页面加载时它直接被勾选,用户不操作也能产生上述默认数据。
此外还有两个"运行时"层面的细节值得延伸:HTML 标记里的 checked 对应 DOM 中的 defaultChecked,它刻画的是"初始默认态";而 input.checked(本挑战断言所访问的属性)反映的是"当前实际选中态",用户后续点击会改变 .checked 但不会改写 defaultChecked。复选框中另一个相关规则是:只有处于选中状态的 checkbox 才会被纳入表单数据,未勾选的不产生任何键值对——这与单选组(始终有一项被提交,除非全组未设默认值且用户未选)行为不同。
无障碍与使用建议
延续本模块此前课程(如 bad87fee1348bd9aedf08834.md)反复强调的最佳实践,seed 代码中的结构本身就示范了几点值得在真实项目中沿用、同时也是本挑战正确通过的前提:
- label 与 input 显式关联:
<label for="indoor">与<input id="indoor">通过id/for配对,点击文字即可切换选中,屏幕阅读器也能正确朗读选项含义; - 单选组共享
name:indoor/outdoor共用indoor-outdoor,保证互斥语义成立,也保证"默认选中其中一项"才有确定含义; - 默认选中值的选择要有业务依据:给单选组设默认值通常用于表达"推荐项"或"最常见取值",从而减少用户操作;而复选框的默认勾选则常用于"订阅/同意"类意向确认——但涉及用户授权、订阅营销等场景时应审慎使用默认勾选,避免违背用户真实意图。
在真实项目中,"记住用户上次选择后再回显"也是常见的 checked 应用场景:服务端返回用户偏好后,前端动态设置 input.checked = true 即可(此时操作的是 DOM 属性而非 HTML 属性),效果与本题在静态标记中书写 checked 在用户可见层面一致。
小结
本挑战用最小改动(每个目标 input 增加一个 checked 属性)演示了 HTML 表单最常用的默认选中机制。通过对照 seed、solution 与四条浏览器断言可以发现:判断题解正确与否的锚点是 DOM 中真实存在的选中状态,单选按钮的组内互斥、复选框的独立多选、以及 checked 与 name/value/defaultChecked 的职责边界,共同构成了这道题希望学习者内化的完整知识图景。在完成本挑战后,可继续同模块的下一课,把 HTML 表单的结构能力延伸到更深的语义化布局学习中。
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 StartedRust0624
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