无障碍 Web 应用和微件概述
===============

大多数 JavaScript 库提供了客户端微件（widget）库，模拟熟悉的桌面界面的行为。滑块、菜单栏、文件列表视图等可以通过 JavaScript、CSS 和 HTML 的组合来构建。由于 HTML4 规范不提供语义上描述这些微件的内置标签，因此开发人员通常会使用通用元素（如 `<div>` 和 `<span>`）。虽然这导致了一个看起来像桌面对应的组件，但标记中通常没有足够的辅助技术可用的语义信息。

问题
--

对于由于某种原因而无法查看屏幕的用户来说，Web 页面上的动态内容都很容易成为问题。股票行情、实时 twitter 消息更新、进度条和类似内容以辅助技术（AT）可能不知道的方式修改 DOM。那就是 ARIA 存在的意义。

*示例 1：没有使用 ARIA 标签（label）的标签页（tab）组件的标记（markup）。标记中没有足够的信息来描述组件的形式和功能。*


```html
<!-- 这是个标签页微件。只看 HTML 标记会知道作用如此吗？ -->
<ol>
  <li id="ch1Tab">
    <a href="#ch1Panel">Chapter 1</a>
  </li>
  <li id="ch2Tab">
    <a href="#ch2Panel">Chapter 2</a>
  </li>
  <li id="quizTab">
    <a href="#quizPanel">Quiz</a>
  </li>
</ol>

<div>
  <div id="ch1Panel">第 1 章的内容在这里</div>
  <div id="ch2Panel">第 2 章的内容在这里</div>
  <div id="quizPanel">测验的内容在这里</div>
</div>
```


*示例 2：标签页微件的视觉样式。用户可能能够通过视觉识别，但是对于辅助技术来说，没有机器可读的语义信息。*

![标签页微件的截图](/zh-CN/docs/Web/Accessibility/An_overview_of_accessible_web_applications_and_widgets/tabs_widget.png)

ARIA
----

**ARIA**（无障碍富互联网应用）使开发者能够通过为标记添加特殊属性来更详细地描述微件。ARIA 旨在填补标准 HTML 标签与动态 Web 应用程序中的桌面样式控件之间的空白，它提供了角色和状态来描述大多数熟悉的 UI 微件的行为。

**警告：** 其中的许多是在浏览器不完全支持现代 HTML 特性时添加的。**开发者应该始终优先使用正确的语义化 HTML 元素而不是使用 ARIA**。

ARIA 规范分为三种不同类型的属性（attribute）：角色、状态和属性（property）。角色描述了 HTML4 中没有的微件，例如滑块、菜单栏、标签页和对话框。属性描述了这些微件的特性，例如它们是否可拖动、是否有必填元素或是否有与之关联的弹出窗口。状态描述了元素的当前交互状态，通知辅助技术它是否繁忙、禁用、选中或隐藏。

ARIA 旨在由浏览器自动解释并转换为操作系统的原生无障碍 API。因此，具有 role="slider" 的元素的控制方式与操作系统上原生滑块的控制方式相同。

与上一代 Web 应用程序相比，这提供了更加一致的用户体验，因为辅助技术用户在使用基于 Web 的应用程序时可以应用他们对桌面应用程序的所有知识。

*示例 3：添加了 ARIA 属性的标签页微件的标记。*


```html
<!-- 现在\*这些\*是标签页了！ -->
<!-- 我们添加了角色属性来描述标签页列表以及每个标签页。 -->
<ol role="tablist">
  <li id="ch1Tab" role="tab">
    <a href="#ch1Panel">Chapter 1</a>
  </li>
  <li id="ch2Tab" role="tab">
    <a href="#ch2Panel">Chapter 2</a>
  </li>
  <li id="quizTab" role="tab">
    <a href="#quizPanel">Quiz</a>
  </li>
</ol>

<div>
  <!-- 注意，我们添加了用于描述这些面板的角色（role）和 aria-labelledby 属性。 -->
  <div id="ch1Panel" role="tabpanel" aria-labelledby="ch1Tab">
    第 1 章的内容在这里
  </div>
  <div id="ch2Panel" role="tabpanel" aria-labelledby="ch2Tab">
    第 2 章的内容在这里
  </div>
  <div id="quizPanel" role="tabpanel" aria-labelledby="quizTab">
    测验的内容在这里
  </div>
</div>
```


ARIA 被所有主流浏览器和许多辅助技术所广泛支持。

### 表现变化

动态的表现（presentational）变化包括使用 CSS 来改变内容的外观（例如在无效数据周围使用红色边框，或者改变选中复选框的背景颜色），以及显示或隐藏内容。

#### 状态变化

ARIA 提供了用于声明 UI 微件当前状态的属性。例如（但不限于）：

`aria-checked`

表示复选框或单选按钮的状态。

`aria-disabled`

表示元素可见但不可编辑或无法操作。

`aria-grabbed`

表示拖放操作中对象的“抓取”状态。

（有关 ARIA 状态的完整列表，请参阅 ARIA 状态和属性列表。）

开发者应该使用 ARIA 状态来指示 UI 微件元素的状态，并使用 CSS 属性选择器以根据状态变化改变视觉外观（而不是使用脚本来更改元素上的类名）。

#### 可见性变化

当内容可见性发生变化时（即，元素被隐藏或显示），开发者应该改变 **`aria-hidden`** 属性的值。应该使用上面描述的技术来声明 CSS，使用 `display:none` 以在视觉上隐藏元素。

下面是一个使用 **`aria-hidden`** 来控制小提示可见性的示例。该示例展示了一个简单的 Web 表单，其中包含与输入字段关联的提示。

在该示例中，小提示的 HTML 标记如下所示。第 9 行将 **`aria-hidden`** 状态设置为 `true`。


```html
<div class="text">
  <label id="tp1-label" for="first">名字：</label>
  <input
 type="text"
 id="first"
 name="first"
 size="20"
 aria-labelledby="tp1-label"
 aria-describedby="tp1"
 aria-required="false" />
  <div id="tp1" class="tooltip" role="tooltip" aria-hidden="true">
    你的名字是可选的
  </div>
</div>
```


标记的 CSS 如下所示。请注意，没有使用自定义类名，只有第 1 行 **`aria-hidden`** 属性的状态。


```css
div.tooltip[aria-hidden="true"] {
  display: none;
}
```


用于更新 **`aria-hidden`** 属性的 JavaScript 如下所示。请注意，脚本只更新 **`aria-hidden`** 属性（第 2 行）；它不需要添加或删除自定义类名。


```js
function showTip(el) {
  el.setAttribute("aria-hidden", "false");
}
```

### 角色变化

ARIA 允许开发者在这个元素本身提供了错误语义或没有语义的情况下，为元素声明语义角色。不应改变元素的角色（**`role`**）。相反，请删除原始元素并用具有新的 **`role`** 的元素替换它。

例如，考虑一个“行内编辑”微件：一个允许用户在不切换上下文的情况下编辑文本的组件。该组件有一个“预览”模式，在该模式下，文本不可编辑，但可激活，以及一个“编辑”模式，在该模式下，文本可编辑。开发者可能会尝试使用只读文本类型的 `<input>` 元素来实现“预览”模式，并将其 ARIA **`role`** 设置为 `button`，然后在“编辑”模式下使元素可写，并删除“编辑”模式下的 **`role`** 属性（因为 `<input>` 元素具有自己的角色语义）。

请不要这样做。应该使用完全不同的元素来实现“预览”模式，例如具有 `button` **`role`** 的 `<div>` 或 `<span>`，并使用文本类型的 `<input>` 元素来实现“编辑”模式。

### 异步内容变化

**备注：** 正在施工中。请参见实时区域。

键盘导航
----

开发者在创建自定义微件时经常忽略对键盘的支持。为了让各种用户都能访问，Web 应用程序或微件的所有功能都应该可以通过键盘控制，而不需要鼠标。在实践中，这通常涉及遵循桌面上类似微件支持的约定，充分利用制表键（tab）、回车、空格和方向键。

传统意义上，Web 上的键盘导航仅限于制表键。用户按制表键将以线性顺序依次聚焦页面上的每个链接、按钮或表单，使用换档键 + 制表键则向后导航。这是一种一维导航形式——前进和后退，一次一个元素。在相当密集的页面上，仅使用键盘的用户通常需要按下制表键数十次才能访问所需的部分。在 Web 上实现桌面风格的键盘约定有可能显著加快许多用户的导航速度。

下面是 ARIA 启用的 Web 应用程序中键盘导航的摘要：

* 制表键应该将焦点放到整个微件上面。例如，导航到菜单栏时**不应该**将焦点放在菜单的第一个元素上。
* 方向键应该允许在微件内进行选择或导航。例如，使用左右方向键应该将焦点移动到上一个和下一个菜单项。
* 当微件不在表单内时，回车和空格都应该选择或激活控件。
* 若在表单内，空格键应该选择或激活控件，而回车键应该将表单提交到默认的地址（action）。
* 如果不确定，请模仿你正在创建的控件的标准桌面行为。

因此，对于上面的标签页微件示例，用户应该能够使用制表键和上档键 + 制表键导航到微件的容器（上面标记中的 `<ol>`）中并从其导航出来。一旦键盘焦点位于容器内，方向键应该允许用户在每个标签之间导航（`<li>` 元素）。从这里开始，约定因平台而异。在 Windows 上，当用户按下方向键时，下一个标签应该自动激活。在 macOS 上，用户可以按回车或空格键来激活下一个标签。键盘导航的 JavaScript 微件的深入教程描述了如何使用 JavaScript 实现此行为。

参见
--

* ARIA
* 键盘导航的 JavaScript 微件
* WAI-ARIA 规范
* WAI-ARIA 创作实践