首页
/ freeCodeCamp 响应式 Web 设计实战:用 input type="date" 构建可访问的日期选择器

freeCodeCamp 响应式 Web 设计实战:用 input type="date" 构建可访问的日期选择器

2026-09-06 15:59:49作者:瞿蔚英Wynne

本文基于 freeCodeCamp 课程中 Responsive Web Design 认证的 Applied Accessibility(应用可访问性)板块,讲解如何用 HTML5 的 input type="date" 构建一个对所有用户(包括键盘用户与读屏用户)都友好的日期输入控件。读完本文,你将理解 input 元素的 type 属性如何决定表单控件形态、浏览器不支持时的优雅降级策略、label 与控件的 for/id 关联原理,并能完成课程中 "Add an Accessible Date Picker" 挑战的完整实现与测试验证。

为什么日期输入属于"可访问性"课题

在 freeCodeCamp 的课程结构中,本题位于 applied-accessibility 板块的第 13 题(共 22 题),该板块整体归属于 Responsive Web Design 超级板块,并纳入 Responsive Web Design 认证。值得注意的是,它的前一道题是 "Improve Form Field Accessibility with the label Element",即通过 label 元素提升表单字段可访问性——本题正是建立在"label 必须与控件正确关联"这一基础之上,进一步处理"控件本身选得对不对"的问题。

原始挑战文档定义在 curriculum/challenges/english/blocks/applied-accessibility/587d778b367417b2b2512aa8.md,其开篇点明核心概念:

表单中经常包含 input 字段,可以用来创建多种不同的表单控件。这个元素上的 type 属性决定了会创建哪种 input 元素。

也就是说,同一个 <input> 标签,靠 type 属性就能变成文本框、提交按钮、密码框、日期选择器等完全不同的控件。前序挑战中大家已经见过 textsubmit 两种类型,而 HTML5 新增了对 date 类型的支持:

  • 在支持的浏览器中:当日期输入框获得焦点时,会弹出原生的日期选择器(date picker)。用户可以直接点选而不是手动输入,这对所有用户都更省事——键盘用户不必逐字符敲入日期,触屏用户可以直接用日历点选。
  • 在不支持的旧浏览器中type="date"自动降级(fallback)为 text 类型,控件仍然可以接收纯文本输入。正因如此,课程文档特别提醒:应当在 labelplaceholder 文本中明确告知用户期望的日期格式,作为兜底提示。

文档给出的最小示例如下:

<label for="input1">Enter a date:</label>
<input type="date" id="input1" name="input1">

这里体现了三个关键的可访问性要点:

  1. label 通过 for 属性指向 inputid:点击标签文字也能聚焦到输入框,且读屏软件会把标签文本作为该控件的名称朗读出来;
  2. type="date":声明控件语义为"日期",让浏览器提供原生日期选择器,并让辅助技术知道用户在填写日期而非任意文本;
  3. name 属性:提交表单时作为键值对的一部分(本例为 input1=...),保证服务端能识别该字段。

挑战任务:给 Camper Cat 的锦标赛调查表添加日期选择器

挑战的场景设定是:Camper Cat 正在组织一场 Mortal Kombat(真人快打)锦标赛,想让参赛选手反馈最合适的日期。任务要求很具体——

添加一个 input 标签,其 type 属性值为 dateid 属性值为 pickdatename 属性值为 date

题目提供的初始代码(seed)如下,其中 <label> 已经就位,等待与之配对的输入控件:

<body>
  <header>
    <h1>Tournaments</h1>
  </header>
  <main>
    <section>
      <h2>Mortal Kombat Tournament Survey</h2>
      <form>
        <p>Tell us the best date for the competition</p>
        <label for="pickdate">Preferred Date:</label>

        <!-- Only change code below this line -->



        <!-- Only change code above this line -->

        <input type="submit" name="submit" value="Submit">
      </form>
    </section>
  </main>
  <footer>&copy; 2018 Camper Cat</footer>
</body>

注意 seed 中的 <label for="pickdate">for 属性值 pickdate 已经提前"约定"了控件必须使用的 id。这不是巧合——如果填出的 idfor 对不上,label 与控件的关联就会失效,键盘用户点击标签无法聚焦、读屏用户也听不到 "Preferred Date" 这个字段名。这正是本课程把"label 可访问性"放在"date picker"之前讲解的原因。

在注释指定区域内补上下面一行即可完成挑战(完整参考答案与官方 solutions 段一致):

<input type="date" id="pickdate" name="date">

最终表单结构为:

<form>
  <p>Tell us the best date for the competition</p>
  <label for="pickdate">Preferred Date:</label>
  <input type="date" id="pickdate" name="date">
  <input type="submit" name="submit" value="Submit">
</form>

提交时,表单将产生 date=2026-09-15(ISO 8601 格式,以浏览器实现为准)这样的数据对,语义清晰、易于服务端解析。

答案如何被自动验证:测试断言逐条解读

freeCodeCamp 的每道挑战都附带断言式测试(chai-assert 风格),本题在挑战文档的 hints 部分给出了四条验证逻辑,正好覆盖了题目要求的每个属性:

// 1. 页面中应恰好有 2 个 input 元素(新加的日期框 + 原有的提交按钮)
assert.lengthOf(document.querySelectorAll('input'), 2);

// 2. 该 input 的 type 属性必须是 "date"
assert.equal(document.querySelector('input')?.getAttribute('type'), 'date');

// 3. id 属性必须是 "pickdate"(与 label 的 for 值对应)
assert.equal(document.querySelector('input')?.getAttribute('id'), 'pickdate');

// 4. name 属性必须是 "date"
assert.equal(document.querySelector('input')?.getAttribute('name'), 'date');

这四条断言揭示了出题意图的完整闭环:

  • 数量断言保证你在表单中只添加了一个控件,而不是重复添加;
  • type 断言保证控件语义正确——如果误写成 type="text",虽然页面上看起来也能输入,但浏览器不会提供原生日期选择器,辅助技术也无法获知"这是日期"这一语义;
  • id 断言保证与既有 <label for="pickdate"> 的绑定关系成立;
  • name 断言保证表单提交数据能被正确识别。

从源码结构看,这类挑战采用 Markdown 分段格式(--description----instructions----hints----seed----solutions--),由 curriculum/schema/challenge-schema.js 定义的模式进行校验;hints 中的代码块即测试断言,seed 是学员编辑的起点,solutions 是用于对照的参考答案。因此"挑战文档本身"既是教程,也是测试与答案的唯一事实来源。

进阶衔接:用 time 元素与 datetime 属性标准化时间

学完日期输入后,课程紧接着的下一题 Standardize Times with the HTML5 datetime Attribute 处理的是"日期/时间显示"的可访问性:HTML5 提供了内联的 time 元素与 datetime 属性,用于把页面中以自然语言写出的日期/时间包裹起来,并提供机器可读的标准格式。

<p>Master Camper Cat officiated the cage match between Goro and Scorpion
<time datetime="2013-02-13">last Wednesday</time>, which ended in a draw.</p>

datetime 属性中的值是辅助技术实际读取的内容——即便页面文字写得口语化("last Wednesday"),读屏软件与搜索引擎仍能解析出精确的 2013-02-13。该挑战的 seed 代码里还展示了带时区的完整时间格式,例如 <time datetime="2016-08-13T20:01Z">August 13<sup>th</sup></time>

两者配合起来就是完整的可访问性时间处理方案:

场景 元素 关键点
让用户输入日期 <input type="date"> 依赖 labelfor/id 绑定;旧浏览器降级为文本时,需在 label 中提示日期格式
让页面展示日期/时间 <time datetime="..."> datetime 属性提供 ISO 格式标准值,供辅助技术与机器读取

小结

本题看似只要求写一行 <input type="date" id="pickdate" name="date">,实际串起了表单可访问性的几条核心原则:用语义化的 type 属性声明控件类型、用 label/for/id 三元组建立可聚焦且可朗读的字段名、通过 name 保证提交数据的可解析性,以及考虑浏览器能力差异时的格式提示兜底。在 freeCodeCamp 课程仓库中,可直接通过 挑战源文件 查看完整的描述、测试断言与参考答案,通过 applied-accessibility 板块定义 查看该题在整个板块中的位置,并通过 certifications 目录下的认证定义 了解它在认证考核中的归属。

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