freeCodeCamp 实战:使用 HTML5 time 元素与 datetime 属性标准化页面中的时间表达
本文基于 freeCodeCamp 响应式网页设计认证(Responsive Web Design)中 "Applied Accessibility"(应用无障碍)模块的一道实战挑战(标准题文件),讲解 HTML5 time 元素与 datetime 属性的用法。读完本文,你将掌握如何用机器可读的标准化格式标注页面中的日期与时间、如何在无障碍场景中为辅助技术提供可靠数据,并能独立完成这道挑战的完整解法与测试验证。
挑战背景:freeCodeCamp 无障碍课程体系中的定位
该挑战属于 freeCodeCamp 课程库中的 Applied Accessibility 模块。从课程结构文件 responsive-web-design.json 可以看到,该模块是 "Responsive Web Design" 认证 superblock 下的第 4 个 block,排在基础 HTML、基础 CSS 与应用视觉设计之后。
模块内部的题目顺序由 applied-accessibility.json 中的 challengeOrder 数组定义。本文对应的挑战 "Standardize Times with the HTML5 datetime Attribute" 排在第 14 位,前面紧邻 "Add an Accessible Date Picker"(使用 <input type="date"> 构建无障碍日期选择器),后面则进入 "Make Elements Only Visible to a Screen Reader by Using Custom CSS"(CSS 视觉隐藏技术)。也就是说,这是一条围绕"日期与时间"主题的连续学习链:先学习表单中的日期输入控件,再学习正文中对时间的语义化标注。
该模块所有题目共享一个贯穿始终的 Camper Cat(忍者猫主题)叙事场景——本页挑战的场景是 Camper Cat 举办《真人快打》(Mortal Kombat)锦标赛后的问卷调查结果公告。
核心概念:time 元素与 datetime 属性
延续日期主题,HTML5 引入了 time 元素和 datetime 属性来标准化页面中的时间表达:
time元素:一个行内(inline)元素,用于包裹页面中的日期或时间文本;datetime属性:承载该日期/时间的标准化格式值。辅助技术(如屏幕阅读器)访问的正是这个属性值,而非元素的可见文本。
其核心价值在于:即使正文中的时间是用非正式、口语化的方式书写(例如 "last Wednesday"),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>
注意可见文本是口语化的 "last Wednesday",但 datetime="2013-02-13" 给出了精确的 ISO 格式日期——这正是"人机双友好"的写法。
datetime 属性支持的格式在挑战的起始代码(seed)中恰好都有体现:
| 格式 | 示例 | 说明 |
|---|---|---|
| 仅日期 | datetime="2016-09-15" |
形如 YYYY-MM-DD,本题要求使用 |
| 日期加时间(UTC) | datetime="2016-08-13T20:01Z" |
完整日期时间,T 分隔符 + Z 表示 UTC 时区,见 seed 中的评论区时间戳 |
实战题目:为调查结果的日期添加 time 标签
任务要求
Camper Cat 的《真人快打》调查结果出炉了!题目要求:用 time 标签包裹文本 Thursday, September 15<sup>th</sup>,并为其添加值为 2016-09-15 的 datetime 属性。
起始代码(seed)
挑战的编辑区起始代码如下(节选自 挑战文件 的 --seed-- 部分):
<body>
<header>
<h1>Tournaments</h1>
</header>
<article>
<h2>Mortal Kombat Tournament Survey Results</h2>
<!-- Only change code below this line -->
<p>Thank you to everyone for responding to Master Camper Cat's survey. The best day to host the vaunted Mortal Kombat tournament is Thursday, September 15<sup>th</sup>. May the best ninja win!</p>
<!-- Only change code above this line -->
<section>
<h3>Comments:</h3>
<article>
<p>Posted by: Sub-Zero on <time datetime="2016-08-13T20:01Z">August 13<sup>th</sup></time></p>
<p>Johnny Cage better be there, I'll finish him!</p>
</article>
<article>
<p>Posted by: Doge on <time datetime="2016-08-15T08:12Z">August 15<sup>th</sup></time></p>
<p>Wow, much combat, so mortal.</p>
</article>
<article>
<p>Posted by: The Grim Reaper on <time datetime="2016-08-16T00:00Z">August 16<sup>th</sup></time></p>
<p>Looks like I'll be busy that day.</p>
</article>
</section>
</article>
<footer>© 2018 Camper Cat</footer>
</body>
可以看到,页面下方的评论区已经用 <time datetime="..."> 正确标注了日期——这就是需要模仿的参照写法;而正文中 "Thursday, September 15th" 这一处还是裸文本,等待你的改造。
参考解答
将目标日期文本用 <time> 包裹并加上 datetime 属性后,目标段落应变为:
<p>Thank you to everyone for responding to Master Camper Cat's survey. The best day to host the vaunted Mortal Kombat tournament is <time datetime="2016-09-15">Thursday, September 15<sup>th</sup></time>. May the best ninja win!</p>
完整解答与起始代码的差异仅在于该 <p> 元素(其余 header、评论区、footer 均保持不变)。
几个实现要点:
<time>必须恰好包裹Thursday, September 15<sup>th</sup>这段内容——包含其中的<sup>th</sup>上标标签,但不要把句尾的句号或前后文字包进去;datetime属性值为仅日期格式2016-09-15(YYYY-MM-DD),与评论区使用的完整日期时间格式不同,因为此处文本只表达了"某一天",没有具体时刻。
测试断言如何验证你的答案
该挑战的自动判题逻辑(位于挑战文件的 --before-all-- 与 --hints-- 部分)通过 DOM 查询来验证答案,其辅助函数结构如下:
const getTimeElement = () => {
const pElement = [...document.querySelectorAll("article > p")]
.filter(x => x?.textContent?.includes("Thank you to everyone for responding to Master Camper Cat's survey."));
return pElement[0] ? pElement[0].querySelector("time") : null;
};
const getDatetimeAttr = () => {
const timeElement = getTimeElement();
return timeElement?.getAttribute("datetime");
};
从源码结构看,判题器先定位包含 "Thank you to everyone..." 文本的 article > p 元素,再在其中查找 time 子元素,最后读取其 datetime 属性值。对应的四条断言依次检查:
// 1. 目标段落中必须存在 time 元素
assert.exists(getTimeElement());
// 2. time 元素内部 HTML 必须精确等于目标文本(含 sup 标签)
assert.strictEqual(getTimeElement()?.innerHTML?.trim(), 'Thursday, September 15<sup>th</sup>');
// 3. datetime 属性不能为空
assert(getDatetimeAttr()?.length != 0);
// 4. datetime 属性值必须精确等于 2016-09-15
assert.equal(getDatetimeAttr(), '2016-09-15');
这组断言揭示了两个容易踩坑的细节:
- 断言 2 用
strictEqual比较innerHTML,意味着包裹范围必须分毫不差——多包一个句号、少包一个<sup>都会失败; - 断言 3 与 4 分开校验"属性存在"和"属性值正确",因此即使写成了
2016-09-15T00:00Z(合法但非题目要求的格式),第 4 条仍会失败。
为什么这对无障碍很重要
time 元素的价值在三个层面:
- 辅助技术层面:屏幕阅读器可以播报
datetime属性给出的标准化时间,而不是逐字朗读口语化文本; - 语义层面:
<time>是 HTML5 的语义化元素,它明确告诉浏览器"这里的时间是一个时间实体",配合datetime形成机器可读的元数据; - 可维护层面:正文可以保留自然的语言风格("last Wednesday"、"Thursday, September 15th"),机器解析则依赖标准化格式,两者互不干扰。
在 freeCodeCamp 的这套模块中,<time> 与上一题的 <input type="date"> 形成互补:前者负责展示层的时间语义化,后者负责表单输入层的日期采集。完成本题后,下一题(仅对屏幕阅读器可见的元素)将转向 CSS 视觉隐藏技术(sr-only),继续延伸"视觉呈现与辅助技术访问解耦"这一核心无障碍思想。
小结
- HTML5
time是行内元素,datetime属性存放标准化的日期/时间值,是辅助设备实际访问的数据源; datetime可取仅日期格式(2016-09-15)或完整日期时间格式(2016-08-13T20:01Z),应按文本实际表达的精度选择;- 本题的关键是把
<time datetime="2016-09-15">精确包裹在Thursday, September 15<sup>th</sup>周围,判题器会通过querySelector与getAttribute("datetime")做精确比对; - 相关素材均可在当前仓库中查阅:挑战文件、模块顺序配置 以及 superblock 结构。
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 StartedRust0625
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