首页
/ freeCodeCamp《Basic HTML and HTML5》精讲:使用 HTML5 required 属性把表单输入设为必填字段

freeCodeCamp《Basic HTML and HTML5》精讲:使用 HTML5 required 属性把表单输入设为必填字段

2026-09-06 19:02:20作者:袁立春Spencer

本文围绕 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.jsonchallengeOrder 列表可以看到,该挑战排在第 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 练习,板块标注的 helpCategoryHTML-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 = 1video = 11quiz = 8 等不同类型,它们共同描述了 freeCodeCamp 挑战的多种形态。而 challenge-schema.js 中的校验规则要求每个挑战必须携带 0~33 范围内的 challengeType 以及合法的 descriptionchallengeFiles 等字段,保证了仓库内所有挑战文件结构统一。

二、核心知识点: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 同样可作用于 checkboxradiofilepasswordemailurlnumber 等输入类型,也可用于 <select><textarea>。对一组同名 radio 来说,required 表达的含义是"该组中必须至少选中一个",这一点在紧随其后的 "Create a Set of Radio Buttons" 等后续挑战中会自然遇到。

2. 浏览器原生反馈

当表单中存在带 required 的空字段时,用户点击提交按钮并不会触发提交动作,浏览器会:

  1. 中止表单的提交流程;
  2. 聚焦到第一个未满足约束的字段;
  3. 弹出一个由浏览器本地化的气泡提示(例如英文环境下的 "Please fill out this field",中文环境会显示相应中文文案);
  4. 该字段同时进入 :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--

挑战指令只有两步,非常聚焦:

  1. 把现有的文本 input 变成 required 字段,这样用户不填写就无法提交表单;
  2. 尝试不输入任何文本直接提交,观察 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 上的增量改动,formbuttonplaceholder 等其他部分均保持原样——这种"每次只引入一个新知识点"的递进设计,正是 Basic HTML and HTML5 板块循序渐进的教学策略。

四、挑战如何被自动判定:读懂 --hints--

1. 判题断言

该挑战的 --hints-- 段落只包含一条验证逻辑:

assert.isTrue(document.querySelector('input').required);

它的判定机制值得拆解:

  • document.querySelector('input'):选取页面文档中第一个 <input> 元素。当前种子页面中恰好只有一个输入框,因此它取到的就是那个需要加 required 的文本框;
  • .required:读取该 DOM 元素的 required 属性(IDL 属性)。浏览器会把 HTML 中的布尔属性反射为 DOM 上的同名布尔属性,所以只要标签里写了 requiredinput.required 即为 true
  • assert.isTrue(...):断言该值为真。若你漏写了 required.required 返回 false,测试失败并提示 "Your text input element should have the required attribute."

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 替代默认气泡,但校验语义本身仍然源自上述约束校验体系。

六、本地复现与继续探索

如果你希望脱离在线平台亲手验证本挑战,可以:

  1. 把上文"初始种子代码"保存为 index.html
  2. 先用不带 required 的版本在浏览器打开,点击 Submit——若为空会直接提交到演示 action(页面跳转/刷新,不校验);
  3. <input> 上补上 required 后重新打开,点击 Submit——浏览器会在提交前拦下空表单并弹出必填提示;
  4. 在开发者工具 Console 里执行 document.querySelector('input').required,可看到返回 true,与仓库 hints 中的断言行为一致。

想深入研究本挑战周边的源码,建议按需阅读:

结语

"Use HTML5 to Require a Field" 是一个小而完整的教学切片:它用一行 required 让学员直观感受 HTML5 声明式表单校验"拦截提交 + 原生提示"的威力,也顺带巩固了此前 form/action/input/placeholder/button 等标签的协同关系。从课程仓库到真实项目,这条主线始终一致:先用 HTML 语义把约束表达清楚,再用 CSS 与少量 JS 优化体验——这正是现代前端表单开发最稳妥的起点。

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