首页
/ freeCodeCamp 课程实战:用 HTML5 audio 元素提升音频内容的可访问性

freeCodeCamp 课程实战:用 HTML5 audio 元素提升音频内容的可访问性

2026-09-06 11:50:09作者:伍霜盼Ellen

本篇基于 freeCodeCamp 课程 applied-accessibility(应用可访问性)块中的一道实战练习展开,讲解如何用 HTML5 的 <audio> 元素为页面引入语义化音频、如何通过 controls 属性获得浏览器原生的播放控制与键盘支持,以及如何为音频内容提供文本替代方案,使听障用户也能访问同等信息。读完后你将掌握:<audio><source> 的正确嵌套写法、布尔属性的使用方式、音频可访问性的完整要求(文本替代 + 同步字幕 + 文字记录),并能通过课程内置的断言测试验证自己的实现。

在课程中的位置

这道练习的 ID 是 587d7789367417b2b2512aa4,位于 applied-accessibility 挑战文件 中。从 课程结构定义 可以看到,该块挑战的完整顺序为:

  1. 为图片添加文本替代(alt 文本)
  2. 了解何时 alt 文本应留空
  3. 用标题元素展示内容层级
  4. 使用 main 元素直达主要内容
  5. article 元素包裹内容
  6. 使用 header / nav / footer 地标帮助屏幕阅读器导航
  7. 使用 audio 元素提升音频内容可访问性(本篇主角)
  8. 后续还有 figurelabelfieldset、日期选择器、对比度等主题

也就是说,本篇练习承接了前面"地标与语义结构"的学习成果,是"给非视觉媒体内容补上可访问通道"这一脉络中的音频篇——前面解决了"让屏幕阅读器知道页面结构",这里解决"让屏幕阅读器用户听到/读到音频内容"。

audio 元素:给音频内容赋予语义

课程的 description 部分给出了核心定义:HTML5 的 <audio> 元素在标记中包裹声音或音频流内容时,赋予内容语义。这一语义意义有两层价值:

  • 浏览器行为:识别出这是媒体资源,提供原生的媒体播放能力;
  • 辅助技术:屏幕阅读器可以据此识别页面中存在音频,并配合替代内容向用户传达信息。

音频内容同样需要**文本替代(text alternative)**才能对听障或重听用户可访问,实现方式有两种:

  1. 页面附近的文字说明(如本练习中 <p> 元素里的 "A sound clip of Zersiax's screen reader in action.");
  2. 指向完整文字记录(transcript)的链接。

课程给出的基础示例如下,注意 <source> 元素支持多个来源的写法——浏览器会按顺序挑选自己能解码的格式:

<audio id="meowClip" controls>
  <source src="audio/meow.mp3" type="audio/mpeg">
  <source src="audio/meow.ogg" type="audio/ogg">
</audio>

其中 type 属性声明了资源的 MIME 类型(如 audio/mpeg 对应 MP3、audio/ogg 对应 OGG),让浏览器在下载文件之前就能判断是否可播放,从而在多来源场景中快速跳过不支持的格式。

controls 属性:布尔属性的典型用法

<audio> 标签支持 controls 属性,作用是显示浏览器默认的播放、暂停及其他控件,并支持键盘操作——这对无障碍至关重要:自绘的播放按钮如果不额外处理焦点与键盘事件,键盘用户将无法操作。

controls 是一个布尔属性(boolean attribute),不需要值,写在标签上即表示开启:

<audio controls>
  ...
</audio>

课程还特别强调了一条多媒体内容的通用要求(注意原文 Note):多媒体内容通常同时包含视觉与听觉成分,需要同步字幕(synchronized captions)文字记录(transcript),视觉和/或听觉障碍用户才能访问它。网页开发者一般不负责制作字幕或 transcript 本身,但必须知道要包含它们

实战:为屏幕阅读器录音添加 audio 元素

练习的 instructions 部分让学习者"放下 Camper Cat",认识可访问性领域推广者、屏幕阅读器使用者 Zersiax(@zersiax),并添加一段他使用屏幕阅读器的真实录音,直观感受屏幕阅读器的工作方式。

课程提供的起始代码(seed)如下,<main> 中已有说明文字,但缺少音频本体:

<body>
  <header>
    <h1>Real Coding Ninjas</h1>
  </header>
  <main>
    <p>A sound clip of Zersiax's screen reader in action.</p>



  </main>
</body>

操作步骤(与 instructions 完全对应):

  1. <p> 元素之后添加一个 <audio> 元素;
  2. <audio> 标签上加入 controls 属性;
  3. <audio> 内部放入一个 <source> 元素,src 属性设为 https://cdn.freecodecamp.org/curriculum/applied-accessibility/screen-reader.mp3type 属性设为 audio/mpeg

课程附带的 Note 值得记住:这段录音听起来可能很快、难以听清,但这正是屏幕阅读器用户的正常使用速度。 这是课程刻意保留"原汁原味"体验的设计。

完成后的参考解答(对应课程的 solutions 部分):

<body>
  <header>
    <h1>Real Coding Ninjas</h1>
  </header>
  <main>
    <p>A sound clip of Zersiax's screen reader in action.</p>
    <audio controls>
      <source src="https://cdn.freecodecamp.org/curriculum/applied-accessibility/screen-reader.mp3" type="audio/mpeg"/>
    </audio>
  </main>
</body>

测试断言:平台如何验证你的实现

课程的 hints 部分内置了一组基于断言的自动测试,逐一检查实现是否达标,这也是该练习的"验收标准",可以直接抄来作为自己写 HTML 时的检查清单:

检查项 断言逻辑
有且仅有一个 <audio> 标签 document.querySelectorAll('audio') 长度为 1
<audio> 必须有闭合标签 正则匹配 <audio.*>[\s\S]*</audio>,且 </audio> 恰好出现 1 次
controls 属性存在 document.querySelector('audio')?.getAttribute('controls') 不为空
有且仅有一个 <source> 标签 document.querySelectorAll('source') 长度为 1
<source> 必须位于 <audio> 内部 在 audio 节点作用域内 :scope source 查询,结果为 1
src 值必须与题目给定的 URL 完全一致 https://cdn.freecodecamp.org/curriculum/applied-accessibility/screen-reader.mp3 做相等比较
type 值必须为 audio/mpeg sourcetype 属性等于 audio/mpeg

从断言设计可以看出几个容易踩的坑:<audio> 必须是成对标签(不能自闭合);<source> 必须嵌套在 <audio> 里而不是放在外面;srctype 的取值必须逐字符匹配。

平台实现佐证:transcript 概念在 freeCodeCamp 中的落地

课程文档要求开发者"知道要包含 transcript",而 freeCodeCamp 自身的客户端代码把这个理念落实成了真实功能。ChallengeTranscript 组件 用原生 <details>/<summary> 结构渲染挑战的字幕/文字记录,默认折叠,<summary> 上标注 aria-expanded={isOpen} 状态供辅助技术感知展开状态;对话类(isDialogue)transcript 走富文本渲染,普通 transcript 则通过 PrismFormatted 展示,并对不同语言的 superBlock 附加 getChallengeContentLangProps 提供的 lang 等属性,确保屏幕阅读器用正确的语言读取内容。这正是"音频/视频挑战 + 可访问文字记录"模式在平台产品侧的实现。

E2E 测试夹具 还能看到平台对音频题目的数据建模:audioData 中同时包含 audio(filename、startTimestamp、finishTimestamp)与 transcript(按说话人组织的文本数组),即"音频片段必须随附文字记录"这一约定被固化进了数据结构和端到端测试之中。这与课程 Note 中"开发者须保证 transcript 被包含"的要求形成呼应。

小结

  • <audio> 为声音内容提供语义,<source> 提供来源与 type(MIME 类型),支持多格式回退;
  • controls 是布尔属性,其存在即开启浏览器原生控件并自带键盘支持;
  • 音频可访问性的完整闭环 = 语义化 <audio> 标签 + 近邻文本说明(或 transcript 链接)+(多媒体场景下的)同步字幕与文字记录;
  • 本课程练习的七条断言可直接作为自查清单:audio 成对出现且唯一、controls 存在、source 位于 audio 内部且 src/type 精确匹配;
  • freeCodeCamp 客户端的 challenge-transcript 组件quiz-audio 夹具 展示了 transcript 从课程理念到产品实现与测试覆盖的完整链路。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391