freeCodeCamp《Basic HTML and HTML5》精讲:使用 HTML5 required 属性把表单输入设为必填字段
本文围绕 freeCodeCamp 开源课程中 Basic HTML and HTML5 板块的 "Use HTML5 to Require a Field" 挑战展开:先说明它在完整课程链中的定位,再逐步讲解
required属性的语法、在浏览器中的原生校验表现、平台自动判题逻辑,最后延伸到约束校验 API 与真实表单开发的注意事项。读完你既能独立完成该挑战,也能把 HTML5 表单必填校验正确应用到自己的页面中。
一、挑战概览与课程定位
"Use HTML5 to Require a Field"(使用 HTML5 将字段设为必填)是 freeCodeCamp 响应式网页设计课程中 Basic HTML and HTML5 板块的一个经典小挑战,它对应英文原版挑战文件 bad87fee1348bd9aedc08830.md。挑战要解决的问题非常具体:让用户在提交表单之前必须先填写某个输入框,否则表单无法提交。
1. 在整个课程中的位置
从板块结构文件 basic-html-and-html5.json 的 challengeOrder 列表可以看到,该挑战排在第 21 位,处在一组围绕"表单"的连续挑战末尾:
| 顺序 | 标题 | 说明 |
|---|---|---|
| 17 | Create a Text Field | 创建文本输入框 <input type="text"> |
| 18 | Add Placeholder Text to a Text Field | 给输入框加 placeholder 提示文字 |
| 19 | Create a Form Element | 用 <form> 包裹输入框并配置 action |
| 20 | Add a Submit Button to a Form | 在表单内添加 type="submit" 的提交按钮 |
| 21 | Use HTML5 to Require a Field | 给输入框加 required,强制必填 |
| 22 | Create a Set of Radio Buttons | 学习单选按钮组 |
也就是说,学员从零开始逐步搭建同一个 CatPhotoApp 页面,先有输入框、再有占位文本、然后是 <form> 与提交按钮,最后通过本挑战让这个表单"真正具备校验能力"。它是一个 legacy-challenge-list(传统列表式)布局下的 HTML 练习,板块标注的 helpCategory 为 HTML-CSS,所属超板块是 responsive-web-design.json 中的 Basic HTML and HTML5。
2. 挑战文件与类型
该挑战的 front matter 关键字段:
id: bad87fee1348bd9aedc08830
title: Use HTML5 to Require a Field
challengeType: 0
dashedName: use-html5-to-require-a-field
其中 challengeType: 0 表示这是一个 HTML(单文件、直接运行 DOM 测试)类型挑战。类型枚举定义在 challenge-types.ts,第 1 行即 const html = 0;,后续还有 js = 1、video = 11、quiz = 8 等不同类型,它们共同描述了 freeCodeCamp 挑战的多种形态。而 challenge-schema.js 中的校验规则要求每个挑战必须携带 0~33 范围内的 challengeType 以及合法的 description、challengeFiles 等字段,保证了仓库内所有挑战文件结构统一。
二、核心知识点:HTML5 的 required 属性
挑战的 --description-- 给出了最核心的结论:你可以把特定表单字段设为必填,这样用户没有填写完之前无法提交表单。
在 HTML5 出现之前,表单提交后是否为空只能靠服务端判断或手写大量 JavaScript;HTML5 原生引入了基于属性的约束校验(Constraint Validation)。把一个字段设为必填,只需在该 input 元素上加上布尔属性 required:
<input type="text" required>
把这个示例放到本挑战的上下文里,即对带占位符的文本框启用必填约束:
<form action="https://www.freecatphotoapp.com/submit-cat-photo">
<input type="text" required placeholder="cat photo URL">
<button type="submit">Submit</button>
</form>
1. 属性语义与支持范围
required是布尔属性:它不需要写值,只要属性名出现在标签中就生效。写成required="required"或required=""效果相同,但最常见的写法就是孤零零一个required。- 它在规范意义上属于"成员约束",由 HTML 标准定义并被现代浏览器原生执行,无需引入任何第三方校验库。
- 它不只适用于
type="text"。根据 HTML 规范,required同样可作用于checkbox、radio、file、password、email、url、number等输入类型,也可用于<select>与<textarea>。对一组同名radio来说,required表达的含义是"该组中必须至少选中一个",这一点在紧随其后的 "Create a Set of Radio Buttons" 等后续挑战中会自然遇到。
2. 浏览器原生反馈
当表单中存在带 required 的空字段时,用户点击提交按钮并不会触发提交动作,浏览器会:
- 中止表单的提交流程;
- 聚焦到第一个未满足约束的字段;
- 弹出一个由浏览器本地化的气泡提示(例如英文环境下的 "Please fill out this field",中文环境会显示相应中文文案);
- 该字段同时进入
:invalid状态,可被 CSS 伪类选中。
整个过程是纯声明式完成的——这正是本挑战让读者"提交一次空表单、亲眼看看提示"想传达的体验。
三、动手完成挑战:从种子代码到标准答案
1. 初始种子代码(--seed-contents--)
挑战起步时的完整 HTML 如下,可以看到表单已经具备 action、占位文本和提交按钮,唯独缺少必填约束:
<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">
<input type="text" placeholder="cat photo URL">
<button type="submit">Submit</button>
</form>
</main>
页面的背景故事:这是一个猫咪照片提交页(CatPhotoApp),用户被要求粘贴一张猫咪图片的 URL。表单的 action 指向一个用于教学演示的假接口地址,本意是说明"提交数据会被发送到哪里"——在本地浏览器里直接点击 Submit 时,页面通常会跳转到该演示地址或提示提交,这并不影响我们观察原生校验的发生时机。
2. 需要做的修改(--instructions--)
挑战指令只有两步,非常聚焦:
- 把现有的文本
input变成required字段,这样用户不填写就无法提交表单; - 尝试不输入任何文本直接提交,观察 HTML5 表单给出的"该字段必填"提示。
对第 1 步,只需在输入框上补一个属性:
<input type="text" required placeholder="cat photo URL">
如果第 2 步你是在 freeCodeCamp 的内置预览(或其他现代浏览器)中完成的,会看到点击 Submit 后没有跳转,而是输入框下方/附近弹出原生校验气泡。
3. 参考答案(--solutions--)
挑战文件自带的完整解答如下(改动点就是 input 上多出的 required):
<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">
<input type="text" required placeholder="cat photo URL">
<button type="submit">Submit</button>
</form>
</main>
对比前后版本可以看出:required 是加在已有 input 上的增量改动,form、button、placeholder 等其他部分均保持原样——这种"每次只引入一个新知识点"的递进设计,正是 Basic HTML and HTML5 板块循序渐进的教学策略。
四、挑战如何被自动判定:读懂 --hints--
1. 判题断言
该挑战的 --hints-- 段落只包含一条验证逻辑:
assert.isTrue(document.querySelector('input').required);
它的判定机制值得拆解:
document.querySelector('input'):选取页面文档中第一个<input>元素。当前种子页面中恰好只有一个输入框,因此它取到的就是那个需要加required的文本框;.required:读取该 DOM 元素的required属性(IDL 属性)。浏览器会把 HTML 中的布尔属性反射为 DOM 上的同名布尔属性,所以只要标签里写了required,input.required即为true;assert.isTrue(...):断言该值为真。若你漏写了required,.required返回false,测试失败并提示 "Your text input element should have therequiredattribute."
2. 从仓库理解测试形态
这份断言代码直接存放在 挑战 Markdown 源文件 的 --hints-- 区块中。freeCodeCamp 会把此类传统(legacy)HTML 挑战的种子代码渲染进可运行页面,再把 hints 里的断言作为单元测试对用户修改后的 DOM 执行。这种"源码即教材、断言即教案"的做法贯穿整个课程仓库:每个挑战都通过 front matter + --description-- + --instructions-- + --hints-- + --seed-contents-- + --solutions-- 的固定结构自洽描述"讲什么、做什么、怎么查、标准答案是什么"。
五、原理纵深:约束校验 API 与真实项目实践
完成挑战只用了 8 个字符,但 required 背后是整套 HTML5 约束校验体系,理解它能让你的必填逻辑更健壮。
1. 约束校验的编程入口
在真实业务里,你可能需要在 JS 侧感知"表单是否可提交",对应方法是:
// 触发校验并返回是否能通过(不显示 UI)
const form = document.querySelector('form');
const ok = form.checkValidity();
// 校验失败时把焦点定位到出错字段并展示浏览器气泡
form.reportValidity();
// 读取单个字段为何不合法
const input = document.querySelector('input');
console.log(input.validationMessage); // 例如 "Please fill out this field."
配合事件可做更细的控制:在 submit 事件里调用 event.preventDefault() 自行处理,或用 invalid 事件监听校验失败。这些都是标准 Web API,任何现代浏览器均支持,与本挑战展示的声明式体验同源。
2. 样式与扩展约束
- 校验状态会映射为伪类:未通过时匹配
:invalid,通过时匹配:valid。开发者可以据此调整边框颜色等视觉反馈,但不要仅用颜色区分错误,应搭配文字提示保证可访问性(例如配合aria-describedby指向错误说明)。 required常常与其他校验属性组合使用,例如限制最小长度minlength、格式匹配pattern,对邮箱类输入用type="email"让浏览器自动做格式校验。- 浏览器对"空值才算未填写"的解释是:空白字符串视为未填写;若你粘贴了空格,在部分浏览器中会因
valueMissing以外的原因(如patternMismatch)被拦下。团队若需要"非空白"级别的强校验,仍要配合pattern或少量 JS。 - 如果某个场景确实允许"跳过校验"(如草稿保存),可以在
<form>上加novalidate,或在提交按钮上使用formnovalidate,但这属于刻意关闭默认行为的例外情形。
3. 无障碍与体验要点
- 每个带
required的输入最好都有对应的<label>,并用for/id关联,让屏幕阅读器用户也能理解该字段; - 必填标记(如星号
*)应配合文字说明,避免单纯依赖颜色或图标; - 原生气泡的样式与文案由浏览器决定、无法跨浏览器统一,因此追求一致体验的生产项目往往会用
setCustomValidity或自定义错误 UI 替代默认气泡,但校验语义本身仍然源自上述约束校验体系。
六、本地复现与继续探索
如果你希望脱离在线平台亲手验证本挑战,可以:
- 把上文"初始种子代码"保存为
index.html; - 先用不带
required的版本在浏览器打开,点击 Submit——若为空会直接提交到演示action(页面跳转/刷新,不校验); - 在
<input>上补上required后重新打开,点击 Submit——浏览器会在提交前拦下空表单并弹出必填提示; - 在开发者工具 Console 里执行
document.querySelector('input').required,可看到返回true,与仓库 hints 中的断言行为一致。
想深入研究本挑战周边的源码,建议按需阅读:
- 挑战英文源文件与 hints:bad87fee1348bd9aedc08830.md
- 同板块前序挑战:Add a Submit Button to a Form、Create a Form Element、Add Placeholder Text to a Text Field
- 板块内挑战顺序编排:basic-html-and-html5.json
- 挑战类型枚举(
html = 0):challenge-types.ts - 挑战文件结构与字段合法性校验规则:challenge-schema.js
结语
"Use HTML5 to Require a Field" 是一个小而完整的教学切片:它用一行 required 让学员直观感受 HTML5 声明式表单校验"拦截提交 + 原生提示"的威力,也顺带巩固了此前 form/action/input/placeholder/button 等标签的协同关系。从课程仓库到真实项目,这条主线始终一致:先用 HTML 语义把约束表达清楚,再用 CSS 与少量 JS 优化体验——这正是现代前端表单开发最稳妥的起点。
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 StartedRust0623
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