概念

语义化 HTML

根据元素的含义而非默认外观来使用 HTML 元素。`<button>` 会被声明为按钮;`<div onclick>` 则什么也不会声明。绝大多数无障碍问题都源于语义的缺失。

语义化 HTML 是指根据元素的含义而非其外观来选择 HTML 元素。<button> 用于操作,<nav> 包裹导航,<table> 承载表格数据。将一个 <div> 样式化为按钮来执行某个操作,是语义失败——即使视觉效果完全相同。

绝大多数无障碍缺陷都源于语义的缺失。几乎每一种辅助技术故障都有相同的根因:用通用元素代替了专为此设计的语义元素。

屏幕阅读器为何依赖语义

屏幕阅读器通过无障碍树将 HTML 内容呈现给用户——这是从 DOM 构建的内部表示,将每个元素映射到角色、名称、状态和属性。无障碍树才是用户实际”听到”的内容。

原生 <button> 在无障碍树中表示为 button "提交"。而样式化为按钮的 <div> 则表示为 generic——屏幕阅读器不会声明任何有用信息,用户也无从发现该 div 是可交互的。

同样的逻辑适用于:

  • 标题(<h1><h6>)——屏幕阅读器允许用户通过标题跳转来浏览页面。<div class="heading"> 不会出现在标题列表中。
  • 列表(<ul><ol><li>)——屏幕阅读器在朗读前会声明”列表,共 5 项”。伪装成列表项的 <div> 则不会。
  • 表单——带有关联 <label><input> 会被读作”电子邮件,编辑文本”。由 div 和 contenteditable 构成的自定义输入框则什么也不会声明。
  • 表格——带有 <th> 行列标题的 <table> 允许用户逐单元格导航,并同步声明标题上下文。由 div 组成的 CSS 网格则不具备此能力。

替换模式

修复方式几乎总是相同的:

  • <div onclick="..."><button>(或用于导航的 <a href>)。
  • <span class="link"><a href>
  • <div role="heading"><h1><h6>
  • 自定义下拉框 → 在设计允许时使用 <select>,否则使用经过模式验证的 ARIA combobox。
  • 以样式化 <div> 构建的标签页 → 参考 ARIA 创作实践指南中的标签页模式。

何时使用 ARIA

ARIA 的第一条规则是:若原生元素能胜任,请勿使用 ARIA。ARIA 角色、状态和属性是补丁,适用于原生 HTML 无法描述所构建组件的场景(树形视图、多选组合框、某些模态框模式)。它们不能替代使用 <button>

实用审计方法

检测代码库中语义退化的最快方法:搜索 divspan 上的 onclick。每一处匹配都是潜在的失败点。次快的方法:搜索 role= 属性。ARIA 在有限场景下是合理的,但大量使用 ARIA 通常意味着原生元素被跳过,而跳过的原因往往是样式需求——但实际上并不需要这样做。