跟着 MDN 学无障碍 Day 3:HTML——无障碍的良好基础

在网页开发过程中,用正确的 HTML 标签表达正确的意图,能够显著提升网页的无障碍性。本文基于 MDN 官方文档,系统性地讲解如何通过 HTML 语义化来最大化网页的可访问性,帮助开发者理解为什么语义化如此重要,以及如何在实际项目中落地实施。

一、HTML 与无障碍的关系

语义化 HTML 是无障碍网页的基石。所谓语义化,指的是尽可能地使用正确的 HTML 标签来表达内容的正确意图。这不仅关乎代码的规范,更直接影响到残疾用户能否顺畅地浏览和使用网页。

语义化的核心价值

一个典型的例子是按钮的实现。很多开发者习惯使用 div 元素来模拟按钮,但这种做法存在严重的无障碍问题:

html 复制代码
<div>Play video</div>

这种写法虽然视觉上可能看起来像个按钮,但屏幕阅读器无法识别它,键盘用户也无法通过 Tab 键聚焦或按回车键激活。正确的做法是使用 button 标签:

html 复制代码
<button>Play video</button>

button 标签不仅提供了默认的按钮样式,更重要的是内置了完整的键盘交互支持:用户可以使用 Tab 键切换焦点,使用回车键或空格键激活按钮。这些功能无需任何额外代码即可获得。

语义化带来的多重收益

在项目初期坚持使用语义化 HTML,并不会增加开发时间,反而能带来以下显著优势:

更便于开发:语义化的 HTML 结构清晰易懂,开发者可以轻松理解页面层次,CSS 和 JavaScript 的操作也更加直观。浏览器提供的默认交互行为可以免费使用,减少了重复造轮子的工作量。

更适配移动端:语义化 HTML 文件通常更轻量,代码量更少,更容易实现响应式设计。移动设备上的屏幕阅读器也能更好地解析内容。

更利于 SEO 优化 :搜索引擎更加重视标题、链接、列表项等语义化标签中的关键词内容。相比非语义化的 div 嵌套,语义化页面更容易被搜索引擎理解和索引,从而获得更好的搜索排名。

实践建议

建议开发者在本地设置屏幕阅读器进行测试。常用的屏幕阅读器包括 NVDA(Windows)、VoiceOver(macOS)和 ChromeVox(Chrome 扩展)。通过亲身体验,可以更直观地理解语义化对无障碍的实际影响。

二、良好的文本内容语义

文本内容是网页信息传递的主要载体,为其提供正确的语义结构是无障碍设计的第一步。

标题与段落结构

屏幕阅读器用户最依赖的功能之一就是通过标题层级来导航页面。合理的标题结构就像书籍的目录,让用户能够快速定位感兴趣的内容。一个良好的语义示例:

html 复制代码
<h1>My heading</h1>

<p>This is the first section of my document.</p>

<p>I'll add another paragraph here too.</p>

<ol>
  <li>Here is</li>
  <li>a list for</li>
  <li>you to read</li>
</ol>

<h2>My subheading</h2>

<p>
  This is the first subsection of my document. I'd love people to be able to
  find this content!
</p>

<h2>My 2nd subheading</h2>

<p>
  This is the second subsection of my content. I think is more interesting than
  the last one.
</p>

屏幕阅读器在浏览这样的内容时,会清晰地朗读每个标题的层级和内容,在每个段落和列表项处停顿,让用户以适合自己的速度阅读。用户还可以使用快捷键快速跳转到下一个或上一个标题,或调出所有标题的列表进行快速导航。

错误的语义实践

相比之下,使用表现性标签和换行符来模拟标题和段落的效果,会给屏幕阅读器用户带来灾难性的体验:

html 复制代码
<font size="7">My heading</font> <br /><br />
This is the first section of my document.
<br /><br />
I'll add another paragraph here too.
<br /><br />
1. Here is
<br /><br />
2. a list for
<br /><br />
3. you to read

这种写法中,屏幕阅读器无法识别任何结构性标记,整个页面被当作一个巨大的文本块一次性朗读出来。用户无法快速跳转,也无法获得内容的整体结构认知。此外,这种代码也难以进行 CSS 样式控制和 JavaScript 操作。

使用通俗易懂的语言

语言表达方式同样影响无障碍性。建议使用清晰简单的语言,避免不必要的行话和俚语。这不仅有利于认知障碍者,也惠及非母语读者、年轻人以及其他所有用户。具体实践中,应尽量避免使用破折号(用"5 到 7"替代"5-7"),展开缩写(用"January"替代"Jan"),并在首次出现时展开首字母缩略词(如写明"超文本标记语言"后再使用"HTML"缩写)。

三、页面布局的无障碍设计

页面布局方式对无障碍体验有着深远的影响,错误的布局方法可能导致屏幕阅读器用户完全无法理解页面结构。

表格布局的问题

过去,开发者常使用 HTML 表格来创建页面布局,将页眉、页脚、侧边栏和主要内容放入不同的表格单元格中。这种做法在现代 Web 开发中已被淘汰,但它所导致的无障碍问题值得引以为戒:

html 复制代码
<table width="1200">
  <tr id="heading">
    <td colspan="6">
      <h1 align="center">Header</h1>
    </td>
  </tr>
  <tr id="nav" bgcolor="#ffffff">
    <td width="200">
      <a href="#" align="center">Home</a>
    </td>
    <td width="200">
      <a href="#" align="center">Our team</a>
    </td>
    <td width="200">
      <a href="#" align="center">Projects</a>
    </td>
    <td width="200">
      <a href="#" align="center">Contact</a>
    </td>
  </tr>
  <!-- 更多布局行 -->
</table>

屏幕阅读器遇到这样的表格布局时,会将其识别为数据表格,要求用户进入表格模式进行浏览。用户需要理解表格的行列结构才能定位内容,这极大地增加了认知负担。特别是当表格嵌套复杂时,屏幕阅读器可能会读出令人困惑的信息,导致用户迷失方向。

HTML5 语义化布局

现代 HTML5 提供了专门的语义元素来描述页面结构,这些元素不仅代码简洁,而且为屏幕阅读器提供了清晰的导航标记:

html 复制代码
<header>
  <h1>Header</h1>
</header>

<nav>
  <!-- 主导航内容 -->
</nav>

<main>
  <article>
    <h2>Article heading</h2>
    <!-- 文章内容 -->
  </article>

  <aside>
    <h2>Related</h2>
    <!-- 侧边栏内容 -->
  </aside>
</main>

<footer>
  <!-- 页脚内容 -->
</footer>

使用这种结构的页面,屏幕阅读器可以清晰地识别出导航区、主要内容区、文章区和侧边栏,用户可以通过快捷键在不同区域间跳转。同时,代码量大幅减少,加载速度更快,维护成本更低。

源码顺序的重要性

除了使用正确的语义元素外,源码的顺序也至关重要。屏幕阅读器按照源码顺序朗读内容,因此即使 CSS 将某个元素移动到页面的其他位置,源码中该元素的位置仍然决定了朗读顺序。建议在编写 HTML 时就按照逻辑顺序排列内容,让屏幕阅读器用户获得与视觉用户一致的浏览体验。

四、UI 控件的键盘可访问性

UI 控件是用户与网页交互的主要途径,确保这些控件可以被键盘操作是无障碍设计的核心要求。

原生控件的键盘支持

浏览器为原生 HTML 表单控件和链接提供了免费的键盘支持。用户可以使用 Tab 键在可聚焦元素间移动,使用 Enter 键激活链接或按钮,使用方向键在 select 下拉列表中选择选项:

html 复制代码
<h1>Links</h1>
<p>This is a link to <a href="https://www.mozilla.org">Mozilla</a>.</p>

<h2>Buttons</h2>
<p>
  <button data-message="This is from the first button">Click me!</button>
  <button data-message="This is from the second button">Click me too!</button>
</p>

<h2>Form</h2>
<form>
  <div>
    <label for="name">Fill in your name:</label>
    <input type="text" id="name" name="name" />
  </div>
  <div>
    <label for="age">Enter your age:</label>
    <input type="text" id="age" name="age" />
  </div>
</form>

这种原生行为无需任何 JavaScript 代码,即可为所有用户提供完整的键盘交互能力。每个可聚焦元素在获得焦点时都会有默认的高亮样式,让用户清楚地知道当前操作的位置。

错误做法:模拟控件

有些开发者使用 div 等非语义元素模拟按钮,这会导致键盘支持完全丢失:

html 复制代码
<div data-message="This is from the first button">Click me!</div>
<div data-message="This is from the second button">Click me too!</div>

这些 div 元素默认不可聚焦,也无法响应键盘事件。虽然可以通过 CSS 使其看起来像按钮,但本质上是伪按钮,对键盘用户和屏幕阅读器用户都不可用。

重建键盘支持的方法

如果确实需要使用非语义元素,可以通过添加 tabindex 属性和 JavaScript 事件来重建部分键盘支持:

html 复制代码
<div data-message="This is from the first button" tabindex="0">Click me!</div>

tabindex="0" 使 div 可以被 Tab 键聚焦。但要支持回车键激活,还需要添加 JavaScript 代码:

javascript 复制代码
document.onkeydown = function (e) {
  if (e.keyCode === 13) {
    document.activeElement.onclick(e);
  }
};

这段代码监听键盘事件,当用户按下回车键时,触发当前聚焦元素的 onclick 处理函数。然而,这种方式存在诸多局限:无法处理空格键激活、无法提供与原生按钮相同的语义信息、增加了代码复杂度和维护成本。因此,强烈建议直接使用原生 HTML 控件。

有意义的文本标签

按钮和链接的文本标签对所有用户都至关重要,对屏幕阅读器用户尤为如此。屏幕阅读器通常提供控件列表功能,用户可以快速查看页面上的所有按钮和链接。因此,标签应该具有自描述性,能够在脱离上下文的情况下被独立理解。

好的链接文本示例:

html 复制代码
<p>
  Whales are really awesome creatures.
  <a href="whales.html">Find out more about whales</a>.
</p>

不好的链接文本示例:

html 复制代码
<p>
  Whales are really awesome creatures. To find more out about whales,
  <a href="whales.html">click here</a>.
</p>

在第一个示例中,链接文本"Find out more about whales"明确说明了点击后会发生什么,即使在链接列表中单独出现也能被理解。而"click here"则完全没有提供任何有用的信息。

表单标签的正确关联

表单控件需要清晰的标签来说明其用途。使用 label 元素并与 input 通过 for 属性关联,是最正确的做法:

html 复制代码
<div>
  <label for="name">Fill in your name:</label>
  <input type="text" id="name" name="name" />
</div>

这种关联方式让屏幕阅读器在聚焦到输入框时朗读对应的标签文本。此外,点击标签文本可以自动聚焦到对应的输入框,增大了可点击区域,对视力和运动障碍用户都有帮助。

五、无障碍数据表格

数据表格包含行列结构信息,需要正确的标记才能让屏幕阅读器用户理解数据之间的关联关系。

基础表格的问题

简单的表格标记虽然能呈现数据,但缺少语义信息来关联行头与数据单元格:

html 复制代码
<table>
  <tr>
    <td>Name</td>
    <td>Age</td>
    <td>Gender</td>
  </tr>
  <tr>
    <td>Gabriel</td>
    <td>13</td>
    <td>Male</td>
  </tr>
</table>

这种表格中,所有单元格都用 td 标记,屏幕阅读器无法区分哪些是表头、哪些是数据。视觉上用户可以看到第一行是表头,但非视觉用户无法获得这一信息。

增强表格无障碍

使用 th 元素标记表头,并通过 scope 属性指定其作用范围,可以构建真正可访问的数据表格:

html 复制代码
<table>
  <caption>学生信息表</caption>
  <tr>
    <th scope="col">Name</th>
    <th scope="col">Age</th>
    <th scope="col">Gender</th>
  </tr>
  <tr>
    <th scope="row">Gabriel</th>
    <td>13</td>
    <td>Male</td>
  </tr>
  <tr>
    <th scope="row">Elva</th>
    <td>8</td>
    <td>Female</td>
  </tr>
</table>

scope="col" 表示该 th 是列标题,scope="row" 表示该 th 是行标题。这样屏幕阅读器就能在朗读每个数据单元格时,同时朗读对应的行标题和列标题,让用户清楚地知道每个数据位于表格的什么位置。

caption 元素为表格提供了标题,相当于图像的 alt 文本。它会在视觉上显示在表格上方,同时也会被屏幕阅读器朗读,帮助所有用户快速了解表格的主题。

六、图像的替代文本

图像内容对于视障用户不可见,必须通过替代文本来传达其信息。正确使用 alt 属性是图像无障碍的核心。

alt 属性的基本用法

alt 属性的内容应该提供图像的直接描述,传达视觉上呈现的关键信息:

html 复制代码
<img
  src="dinosaur.png"
  alt="A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a human, with small arms, and a large head with lots of sharp teeth." />

屏幕阅读器会朗读这段 alt 文本,让用户理解图像的内容。注意 alt 文本应该简洁准确,描述图像本身传达的信息,而非提供额外的背景知识或主观评价。

不提供 alt 属性的后果

如果图像没有 alt 属性,屏幕阅读器通常会读出图像的文件名,这可能毫无意义:

html 复制代码
<img src="dinosaur.png" />

这样会被朗读为"dinosaur.png,图像",用户只能通过文件名猜测内容。更糟糕的是,如果文件是相机生成的如"IMG_20240101_123456.jpg",用户完全无法获得任何有用信息。

装饰性图像的处理

对于纯粹装饰性的图像,应该使用空的 alt 属性:

html 复制代码
<h3>
  <img src="article-icon.png" alt="" />
  Tyrannosaurus Rex: the king of the dinosaurs
</h3>

alt 属性会让屏幕阅读器忽略该图像(或仅提示"图像"而不朗读任何描述),这样用户就不会被无关的装饰元素干扰。另一种做法是使用 role="presentation" 属性,达到同样的效果。

aria-labelledby 的使用

如果一段文本已经被用来描述图像,可以使用 aria-labelledby 属性来引用该文本段落,避免重复书写:

html 复制代码
<img src="dinosaur.png" aria-labelledby="dino-label" />

<p id="dino-label">
  The Mozilla red Tyrannosaurus Rex: A two legged dinosaur standing upright like
  a human, with small arms, and a large head with lots of sharp teeth.
</p>

这种方法特别适用于需要为多个图像使用相同描述文本的场景,或者描述内容较长、不适合放在 alt 属性中的情况。

figure 与 figcaption

HTML5 的 figurefigcaption 元素可以将图像与标题关联起来:

html 复制代码
<figure>
  <img src="dinosaur.png" alt="The Mozilla Tyrannosaurus" />
  <figcaption>
    A red Tyrannosaurus Rex: A two legged dinosaur standing upright like a
    human, with small arms, and a large head with lots of sharp teeth.
  </figcaption>
</figure>

figcaption 提供的标题对所有用户可见,并且为图像提供了额外的上下文信息。虽然目前屏幕阅读器对 figcaption 与图像的关联支持尚不完善,但这种结构对于 CSS 样式和代码组织仍然非常有益。

七、总结

HTML 语义化是无障碍网页开发的基石。通过使用正确的 HTML 标签表达正确的意图,开发者可以在不增加额外工作量的情况下,为残疾用户提供完整的浏览体验。

核心实践要点包括:使用标题、段落、列表等元素构建清晰的内容结构;采用 HTML5 语义化布局元素而非表格布局;使用 buttoninputa 等原生 UI 控件而非模拟元素;为所有表单控件关联 label 标签;使用 thscope 构建可访问的数据表格;为图像提供有意义的 alt 文本或使用空的 alt 属性处理装饰性图像。

语义化的价值不仅体现在无障碍方面,它还能让代码更清晰易维护、更适配移动设备、更有利于搜索引擎优化。每一个为无障碍所做的改进,都在让网页变得更加包容,让信息真正地服务于所有人。