enable-background - SVG：可缩放矢量图形

enable-background
=================

**SVG 2:** 不再推荐使用该特性。虽然一些浏览器仍然支持它，但也许已从相关的 web 标准中移除，也许正准备移除或出于兼容性而保留。请尽量不要使用该特性，并更新现有的代码；参见本页面底部的兼容性表格以指导你作出决定。请注意，该特性随时可能无法正常工作。

该 **`enable-background`** 属性指定如何管理背景图像的累积。

\*\*注意：\*\*作为演示文稿属性，`enable-background`可以用作 CSS 属性。

作为表示属性，它可以应用于任何元素，但仅对以下 11 个元素有效：`<a>`，`<defs>`，`<字形>`，`<g>`，`<marker>`，`<mask>`，`<missing-glyph>`，`<pattern>`，`<svg>`，`<switch>`和`<symbol>`

上下文注释
-----

| 值 | `accumulate`| `new`[ `<x>` `<y>` `<width>` `<height>`]？ |
| --- | --- |
| 默认值 | `accumulate` |
| 可动画的 | 没有 |

`accumulate`

如果祖先容器元素的属性值为`enable-background: new`，则当前容器元素内的所有图形元素都将呈现到父容器元素的背景图像画布上以及目标设备上。否则，没有当前的背景图像画布，因此图形元素仅渲染到目标设备上。

`new [ <x> <y> <width> <height> ]?`

 该值使当前容器元素的子代能够访问背景图像。它还指示建立了新的（即最初为透明的黑色）背景图像画布，并且实际上，除了将当前容器元素的所有子对象呈现到目标设备上之外，还应将其呈现到新的背景图像画布中。The optional `<x>`, `<y>`, `<width>`, and `<height>` parameters are `<number>` values that indicate the subregion of the container elementʼs user space where access to the background image is allowed to happen. Those values act as a clipping rectangle on the background image canvas.
 Negative values for `<width>` or `<height>` are forbidden. If one, two, or three values are specified or if neither `<width>` nor `<height>` are specified, the `BackgroundImage` and `BackgroundAlpha` of a filter primitive are processed as if background image processing were not enabled.

Specifications
--------------

| Specification |
| --- |
| Scalable Vector Graphics (SVG) 1.1 (Second Edition) # EnableBackgroundProperty |

Browser compatibility
---------------------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


kernelMatrix - SVG：可缩放矢量图形

kernelMatrix
============

用于 order 属性定义一列 <number> 为 `<feConvolveMatrix>` 元素构成核矩阵。值之间用空格或逗号分开。<number> 的数量必须等于在 `order` 属性中定义的 <orderX> 和 <orderY> 的乘积。

Usage context
-------------

| Categories | None |
| --- | --- |
| Value | T<.2Fvar>s"><list of number> |
| Animatable | Yes |

Example
-------

Elements
--------

下面的元素可以使用`kernelMatrix 属性`

* `<feConvolveMatrix>`
规范
--

| Specification |
| --- |
| Filter Effects Module Level 1 # element-attrdef-feconvolvematrix-kernelmatrix |


fill-rule - SVG：可缩放矢量图形

fill-rule
=========

**`fill-rule`** 是一个表现属性，它定义了用来确定一个多边形内部区域的算法。

**备注：** 作为一个表现属性，fill-rule 可以被用于 CSS。

作为一个表现属性，它可以被应用于任何元素，但只会在以下元素中有效：

* `<path>`
* `<polygon>`
* `<polyline>`
* `<text>`
* `<textPath>`
* `<tref>`
* `<tspan>`

如何判断一个路径组成的多边形的内部区域，从而给它上色，对于一个简单的、没有交错的路径来说，是很显然的；然而，对于一个更为复杂的路径，比如一条与自身相交的路径，或者是这条路径上的其中一段将另一段包围着，要解释什么是“内部”，就不再这么显然了。

示例
--
```

html,
body,
svg {
  height: 100%;
}
```

```html
<svg viewBox="-10 -10 220 120" xmlns="http://www.w3.org/2000/svg">
  <!-- fill-rule 的默认值 -->
  <polygon
 fill-rule="nonzero"
 stroke="red"
 points="50,0 21,90 98,35 2,35 79,90" />

  <!--
 从这个形状的中心到无穷远处有两条路径段（红色部分），因此
 该区域被认为是形状外部，并且没有被填充。
 -->
  <polygon
 fill-rule="evenodd"
 stroke="red"
 points="150,0 121,90 198,35 102,35 179,90" />
</svg>
```

用法
--

| 类别 | 外观属性 |
| --- | --- |
| 值 | nonzero | evenodd |
| 默认值 | nonzero |
| 可变性 | Yes |
| 规范文档 | SVG 1.1 (2nd Edition) |

`fill-rule` 属性为如何确定一个形状的内部（即可以被填充的区域）提供了两个可选值：

### nonzero

这个值确定了某点属于该形状的“内部”还是“外部”：从该点向任意方向的无限远处绘制射线，然后检测形状与射线相交的位置。从 0 开始统计，路径上每一条从左到右（顺时针）跨过射线的线段都会让结果加 1，每条从右向左（逆时针）跨过射线的线段都会让结果减 1。当统计结束后，如果结果为 0，则点在外部；如果结果不为 0，则点在内部。

#### Example
```

html,
body,
svg {
  height: 100%;
}
```

```html
<svg viewBox="-10 -10 320 120" xmlns="http://www.w3.org/2000/svg">
  <!-- nonzero 填充规则被用于路径段会相交的形状上的效果 -->
  <polygon
 fill-rule="nonzero"
 stroke="red"
 points="50,0 21,90 98,35 2,35 79,90" />

  <!--
 nonzero 填充规则被用于一个形状在另一形状内部的效果
 这两个正方形的路径段方向相同（都是顺时针）
 -->
  <path
 fill-rule="nonzero"
 stroke="red"
 d="M110,0 h90 v90 h-90 z
 M130,20 h50 v50 h-50 z" />

  <!--
 这个例子与第二个例子几乎相同，唯一的区别是：两个形状的路径段方向相反
 外面的正方形是顺时针，里面的正方形则是逆时针
 -->
  <path
 fill-rule="nonzero"
 stroke="red"
 d="M210,0 h90 v90 h-90 z
 M230,20 v50 h50 v-50 z" />
</svg>
```

### evenodd

这个值用确定了某点属于该形状的“内部”还是“外部”：从该点向任意方向无限远处绘制射线，并统计这个形状所有的路径段中，与射线相交的路径段的数量。如果有奇数个路径段与射线相交，则点在内部；如果有偶数个，则点在外部。

#### Example
```

html,
body,
svg {
  height: 100%;
}
```

```html
<svg viewBox="-10 -10 320 120" xmlns="http://www.w3.org/2000/svg">
  <!-- evenodd 填充规则被用于路径段会相交的形状上的效果 -->
  <polygon
 fill-rule="evenodd"
 stroke="red"
 points="50,0 21,90 98,35 2,35 79,90" />

  <!--
 evenodd 填充规则被用于一个形状在另一形状内部的效果
 这两个正方形的路径段方向相同（都是顺时针）
 -->
  <path
 fill-rule="evenodd"
 stroke="red"
 d="M110,0 h90 v90 h-90 z
 M130,20 h50 v50 h-50 z" />

  <!--
 这个例子与第二个例子几乎相同，唯一的区别是：两个形状的路径段方向相反
 外面的正方形是顺时针，里面的正方形则是逆时针
 -->
  <path
 fill-rule="evenodd"
 stroke="red"
 d="M210,0 h90 v90 h-90 z
 M230,20 v50 h50 v-50 z" />
</svg>
```

规范
--

| Specification |
| --- |
| Scalable Vector Graphics (SVG) 2 # WindingRule |

浏览器兼容性
------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


事件处理器（概述） - 事件参考

事件处理器（概述）
=========

事件是浏览器窗口内触发的信号，用于通知浏览器或操作系统环境的变化。程序员可以创建用于在事件触发时运行的*事件处理器*代码，使网页能够适当地响应变化。

本页提供了有关如何使用事件和事件处理器的非常简短的“提醒”。新开发人员应阅读事件介绍。

有哪些可用事件？
--------

事件记录在产生事件的 JavaScript 对象的页面中和/或页面下方。例如，要了解浏览器窗口或当前文档触发的事件，请参阅 `Window` 和 `Document` 中的事件部分。

你可以使用事件参考查找哪些 JavaScript 对象会触发特定 API 的事件，例如动画、媒体等。

注册事件处理器
-------

有两种推荐的注册处理器的方法。可以将事件处理器代码赋值给目标元素对应的 *onevent* 属性，或使用 `addEventListener()` 方法将处理器注册为元素的监听器，从而在事件触发时运行事件处理器的代码。无论哪种情况，处理器都将接收一个符合 `Event` 接口的对象。主要区别在于可以使用事件监听器方法添加（或删除）多个事件处理器。

**警告：** 不推荐使用 HTML onevent 属性设置事件处理器的第三种方法！它们会使标签变长，从而降低了可读性且变得难以调试。有关详细信息，请参阅内联事件处理器。

### 使用 onevent 属性

按照惯例，触发事件的 JavaScript 对象都有相应的“onevent”属性（以事件名称加前缀“on”命名）。当事件触发时，这些属性会被调用以运行相关的处理器的代码，也可能被你自己的代码直接调用。

要设置事件处理器的代码，只需将其赋值给相应的 onevent 属性即可。一个元素的每个事件只能分配一个事件处理器。如果需要，可以通过将另一个函数赋值给相同的属性来替换处理器。

下面我们将展示如何使用 `onclick` 属性为 `click` 事件设置一个简单的 `greet()` 函数。

```js
const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.onclick = greet;
```

请注意，代表事件的对象会作为第一个参数传递给事件处理器。此事件对象实现或派生自 `Event` 接口。

### EventTarget.addEventListener

在元素上设置事件处理器的最灵活的方法是使用 `EventTarget.addEventListener` 方法。这种方法允许为一个元素分配多个监听器，并在需要时*删除*监听器（使用 `EventTarget.removeEventListener` 方法）。

**备注：** 添加和删除事件处理器的功能允许你在不同情况下执行不同的操作，例如，让同一个按钮执行不同的操作。此外，在更复杂的程序中，清理旧的或未使用的事件处理器可以提高效率。

下面我们展示了如何将一个简单的 `greet()` 函数设置为 `click` 事件的监听器/事件处理器（如果需要，你可以使用匿名函数代替具名函数）。请再次注意，事件（event）会作为第一个参数传递给事件处理器。

```js
const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.addEventListener("click", greet);
```

该方法还可以使用其他参数/选项来控制捕获和删除事件的方式。更多信息请参阅 `EventTarget.addEventListener` 参考页面。

#### 使用终止信号

事件监听器的一个显著特点是可以使用终止信号同时清理多个事件处理器。

具体做法是将相同的 `AbortSignal` 传递给所有你想要可以一起移除的事件处理器的 `addEventListener()` 调用。然后，你可以在拥有“AbortSignal”（终止信号）的控制器上调用 `abort()`，这样就能移除通过该信号添加的所有事件处理器。例如，要添加一个可以使用 `AbortSignal` 移除的事件处理器：

```js
const controller = new AbortController();

btn.addEventListener(
  "click",
  (event) => {
    console.log("greet:", event);
  },
  { signal: controller.signal },
); // 将 AbortSignal 传递给该处理器
```

然后，通过上面代码创建的事件处理器可以这样移除：

```js
controller.abort(); // 移除与此控制器关联的任何/所有事件处理器
```


创建和触发事件 - 事件参考

创建和触发事件
=======

本文演示了如何创建和分派 DOM 事件。这些事件通常称为**合成事件**，而不是浏览器本身触发的事件。

创建自定义事件
-------

可以使用 `Event` 构造函数创建事件，如下所示：

```js
const event = new Event("build");

// 监听该事件。
elem.addEventListener(
  "build",
  (e) => {
    /\* … \*/
  },
  false,
);

// 分派该事件。
elem.dispatchEvent(event);
```

上述代码使用了 EventTarget.dispatchEvent() 方法。

绝大多数现代浏览器中都支持这个构造函数。要了解更为复杂的方法，可参考下面的过时的方式。

### 添加自定义数据——CustomEvent()

 要向事件对象添加更多数据，可以使用 CustomEvent 接口，**detail** 属性可用于传递自定义数据。
 例如，可以像这样创建事件：

```js
const event = new CustomEvent("build", { detail: elem.dataset.time });
```

下面的代码允许你在事件监听器中访问更多的数据：

```js
function eventHandler(e) {
  console.log(`The time is: ${e.detail}`);
}
```

### 过时的方式

早期的创建事件的方法使用了受 Java 启发的 API。下面是一个使用 `document.createEvent()` 的示例：

```js
// 创建事件。
const event = document.createEvent("Event");

// 定义事件的名称为“build”。
event.initEvent("build", true, true);

// 监听该事件。
elem.addEventListener(
  "build",
  (e) => {
    // e.target 与 elem 相匹配
  },
  false,
);

// 目标（target）可以是任何元素或其他 EventTarget。
elem.dispatchEvent(event);
```

### 事件冒泡

通常需要从子元素触发事件，并让其祖先捕获它；且可以带有数据：

```html
<form>
  <textarea></textarea>
</form>
```

```js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

// 创建一个新事件，允许冒泡，并提供要传递给“detail”属性的任何数据
const eventAwesome = new CustomEvent("awesome", {
  bubbles: true,
  detail: { text: () => textarea.value },
});

// 表单（form）元素监听自定义的“awesome”事件，然后在控制台打印传递的 text() 方法的输出
form.addEventListener("awesome", (e) => console.log(e.detail.text()));

// 当用户输入时，表单中的文本区域会分派/触发事件，并以自身为事件的起点
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));
```

### 动态创建和分派事件

元素可以监听尚未创建的事件：

```html
<form>
  <textarea></textarea>
</form>
```

```js
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

form.addEventListener("awesome", (e) => console.log(e.detail.text()));

textarea.addEventListener("input", function () {
  // 动态创建并分派/触发一个事件
  // 注意：我们还可以使用“函数表达式”（而不是“箭头函数表达式”），这样“this”将表示该元素
  this.dispatchEvent(
    new CustomEvent("awesome", {
      bubbles: true,
      detail: { text: () => textarea.value },
    }),
  );
});
```

触发内置事件
------

下面的示例演示了使用 DOM 方法在复选框上模拟点击（click）（即，通过编程方法生成 click 事件）。参见这个动态示例。

```js
function simulateClick() {
  const event = new MouseEvent("click", {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  const cb = document.getElementById("checkbox");
  const cancelled = !cb.dispatchEvent(event);

  if (cancelled) {
    // 处理器调用了 preventDefault。
    alert("cancelled");
  } else {
    // 没有处理器调用 preventDefault。
    alert("not cancelled");
  }
}
```

参见
--

* CustomEvent()
* `document.createEvent()`
* `Event.initEvent()`
* `EventTarget.dispatchEvent()`
* `EventTarget.addEventListener()`


ARIA - 无障碍

ARIA
====

无障碍富互联网应用（Accessible Rich Internet Applications，**ARIA**）是一组角色和属性，用于定义使残障人士更易于访问 web 内容和 web 应用程序（尤其是使用 JavaScript 开发的应用程序）的方法。

它补充了 HTML，以便在没有其他机制时可以将应用程序中常用的交互和小部件传递给辅助技术。例如，ARIA 支持无障碍 JavaScript 小部件、表单提示和错误消息、实时内容更新等。

**警告：** 许多这些小部件在现代浏览器中都已经完全支持。如果有正确语义的 HTML 元素存在的话，**开发人员应该更喜欢使用这样的元素而不是使用 ARIA**。例如，原生元素具有内置的键盘无障碍、角色和状态。但是，如果你选择使用 ARIA，则你有责任在脚本中模仿等效的浏览器行为。

使用 ARIA 的第一规则是“如果你能够使用原生的 HTML 元素或属性，并且有你需要但已经建立在里面的语义和行为，而不是重新调整元素的用途并添加 ARIA 角色、状态或者属性来使它更加无障碍，那么你就应该如此。”

**备注：** 有个说法叫做“ARIA 宁缺毋滥”。在 WebAim 对超过 100 万个主页的调查中，他们发现，有 ARIA 存在的主页比那些没有 ARIA 的，多检测出了平均 41% 的错误。尽管 ARIA 是为了使网页更加无障碍而设计的，但是如果使用不当，可能适得其反。

这是进度条小部件的标记：

```html
<div
 id="percent-loaded"
 role="progressbar"
 aria-valuenow="75"
 aria-valuemin="0"
 aria-valuemax="100"></div>
```

这个进度条是使用 `<div>` 构建的，没有任何意义。我们加入 ARIA 角色和属性以添加意义。在这个例子中，`role="progressbar"` (en-US) 属性告知浏览器，这个元素实际上是一个由 JavaScript 驱动的进度条小部件。`aria-valuemin` (en-US) 和 `aria-valuemax` (en-US) 属性指定进度条的最小值和最大值，`aria-valuenow` (en-US) 描述进度条的当前状态，因此必须使用 JavaScript 保持更新。

除了将它们直接放置在元素中之外，还可以将 ARIA 属性添加到元素中，并使用 JavaScript 代码动态更新，如下所示：

```js
// 在 DOM 中，寻找进度条 <div>。
var progressBar = document.getElementById("percent-loaded");

// 设置其 ARIA 属性和状态，
// 这样辅助技术知道它是哪一种部件。
progressBar.setAttribute("role", "progressbar");
progressBar.setAttribute("aria-valuemin", 0);
progressBar.setAttribute("aria-valuemax", 100);

// 创建可以在任何时候调用的函数，
// 以更新进度条的值。
function updateProgress(percentComplete) {
  progressBar.setAttribute("aria-valuenow", percentComplete);
}
```

所有对非辅助技术的可用的内容都应该对辅助技术可用。类似地，不应包含针对辅助技术用户使用但对于不使用辅助技术的用户无法访问的任何特性。这个进度条需要有相应的样式，从而看起来像进度条。

如果使用原生的 `<progress>` 元素，则会简单得多：

```html
<progress id="percent-loaded" value="75" max="100">75 %</progress>
```

**备注：** `<progress>` 元素不允许 `min` 属性，最小值永远为 0。

**备注：** HTML 地标元素（`<main>`、`<header>`、`<nav>` 等）具有内置的 ARIA 角色，因此有无需复制它们。

支持
--

与任何其他 Web 技术一样，ARIA 也有不同程度的支持。支持基于所使用的操作系统和浏览器，以及与之交互的辅助技术类型。此外，操作系统、浏览器和辅助技术的版本也是影响因素。较旧的软件版本可能不支持某些 ARIA 角色、仅部分支持或误报其功能。

同样重要的是要承认一些依赖辅助技术的人不愿意升级他们的软件，因为害怕失去与他们的计算机和浏览器交互的能力。因此，尽可能使用语义化的 HTML 元素很重要，因为语义 HTML 对辅助技术的支持要好得多。

使用实际辅助技术测试你编写的 ARIA 也很重要。就像浏览器模拟器和模拟器不是测试完全支持的有效解决方案一样，代理辅助技术解决方案不足以完全保证功能。

参考
--

ARIA 角色

包含了 MDN 中讨论的所有 WAI-ARIA 角色的参考页面。

ARIA 状态和属性

包含了 MDN 中讨论的所有 WAI-ARIA 状态和属性的参考页面。

标准化工作
-----

WAI-ARIA 规范

W3C 规范本身。

WAI-ARIA 创作实践

官方最佳实践记录了如何最好地对常见小部件和交互进行 ARIA 化。一个很好的资源。

脚本小部件的 ARIA
-----------

编写可通过键盘导航的 JavaScript 小部件

`<input>`、`<button>` 等内置元素具有内置键盘辅助功能。如果你使用 `<div>` 和 ARIA 来“伪造”这些，则必须确保你的小部件可通过键盘访问。

实时区域

实时区域向屏幕阅读器提供有关如何处理页面内容更改的建议。

视频
--

以下演讲是了解 ARIA 的好方法：

ARIA, Accessibility APIs and coding like you give a damn! – Léonie Watson


移动无障碍清单 - 无障碍

移动无障碍清单
=======

该文档为移动应用开发者提供一个无障碍需求的简要清单。此文档将随着技术模式的发展而不断演进。

颜色
--

* 颜色对比度**必须**遵循 WCAG 2.0 AA 等级需求：
    + 普通文本的对比率为 4.5:1（小于 18 磅或黑体 14 磅）
    + 大文本对比率为 3:1（大于等于 18 磅或黑体 14 磅）【译者注：字体单位为 point、PT】
* 颜色传递的信息，**必须**也通过其他方式标明（例如，链接文本中的下划线）

**备注：** Jon Snook 开发的 颜色对比度检查器 - Colour Contrast Checker 可以轻松检查前景和背景的对比度。同样，Tanaguru Contrast-Finder 这个工具能做类似的检查，并且会推荐你考虑使用类似的更好的对比度

可视化
---

* **不**使用用于隐藏内容的技巧处理视觉效果，例如，不透明度为零，z-index 规则，离屏位置。
* 当前可见的屏幕之外的内容，**必须**是不可见的。（特别是单一页面应用中包含多个卡片选项）:
    + **使用** `hidden` 特性或 `visibility` 或 `display` 样式属性。
    + 除非不可避免，**不应该**使用 `aria-hidden` 特性。
焦点
--

* 所有可激活元素**必须**可被聚焦：
    + 标准控件，如链接、按钮、表单域默认可被聚焦。
    + 非标准控件**必须**分配给它们一个适当的 ARIA Role 如 `button`，`link` 或者 `checkbox`。
* 焦点应该是有逻辑顺序，且方式一致。
文本等效
----

* 应用中，每个展示的非文本元素都**必须**提供等效文本。
    + 恰当的位置使用 *alt* 和 *title*（请参考 Steve Faulkner 的帖子 - 关于 Using the HTML title attribute 。）
    + 如果上面的特性不适用，使用恰当的ARIA Properties，比如 `aria-label`, `aria-labelledby`, 或 `aria-describedby`.
* **必须**避免文本图像。
* 所有的表单控件**必须**有标签 (`<label>` elements) ，以便于读屏用户的使用。
状态处理
----

* 标准控件，如单选按钮和复选是通过操作系统处理的，而其他自定义控件的状态改变需要通过 ARIA States ，如 `aria-checked`, `aria-disabled`, `aria-selected`, `aria-expanded`,和 `aria-pressed`.
General Guidelines 常规指南
-----------------------

* 应用必须提供标题。【译者注：此处的标题为 title】
* 标题**不能**破坏层次结构。【译者注：此处的标题为 headings】

```html
<h1>Top level heading</h1>
<h2>Secondary heading</h2>
<h2>Another secondary heading</h2>
<h3>Low level heading</h3>
```

* 应使用 ARIA Landmark Roles 描述应用或文档的结构，如 `banner`, `complementary`, `contentinfo`, `main`, `navigation`, `search`.
* 触摸事件处理器，只能通过 `touchend` 事件触发。
* 触摸目标必须足够大，方便用户交互 (参考 BBC Mobile Accessibility Guidelines 关于触摸目标尺寸的指南)

**备注：** Tanaguru's automated accessibility testing service 提供一个有效的方法，排查网页上的，或者是可安装的 Web 应用中无障碍问题（如，Firefox OS）。tanaguru.org，你可以参与该项目或者发现更多技术实现。

**备注：** The 该文档的最初版本 - original version of this document 是由 Yura Zenevich 完成。


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

无障碍 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 创作实践


键盘导航的 JavaScript 微件 - 无障碍

键盘导航的 JavaScript 微件
===================

网页应用经常使用 JavaScript 来模拟桌面组件，比如菜单、树状视图、富文本以及标签面板等。网页中这些微件通常是由 `<div>` 和 `<span>` 等元素组合而成，并不是原生的，也不会提供对应的桌面组件所拥有的键盘功能。本文档主要描述能让 JavaScript 微件使用键盘访问的技术。

利用 tabindex
-----------

默认情况下，当人们使用 tab 键浏览网页时，只有交互式元素（如链接、表单控件）才会被聚焦。通过 `tabindex` 全局属性，作者也可以使其他元素成为焦点。当设置为 `0` 时，元素可通过键盘和脚本聚焦。当设置为 `-1` 时，元素可被脚本聚焦，但不会成为键盘聚焦顺序的一部分。

使用键盘时，元素获得焦点的顺序默认为源顺序。在特殊情况下，作者可能希望重新定义顺序。为此，作者可以将 `tabindex` 设置为任意正数。

**警告：** 避免为 `tabindex` 使用正值。具有正 `tabindex` 值的元素会被放在页面上默认的交互式元素之前，这意味着页面作者在使用一个或多个 `tabindex` 正值时，必须为页面上所有可聚焦元素设置（并维护）`tabindex` 值。

下面表格阐述主流浏览器中 `tabindex` 的行为：

| `tabindex` 属性 | 可用鼠标或 JavaScript 语句 `element.focus()` 获取焦点 | 可使用 Tab 键导航获取焦点 |
| --- | --- | --- |
| 不存在 | 遵循所在平台针对此元素的默认行为（表单控件、链接等） | 遵循所在平台针对此元素的默认行为 |
| 负值（也就是说，`tabindex="-1"`） | 是 |
 否；作者必须使用 `focus()` (en-US)
 来聚焦该元素。可以在方向键或者其他键的响应里面做。
  |
| 零（也就是说，`tabindex="0"`） | 是 | 相对于元素在文档中的位置，以 tab 顺序排列（请注意，交互式元素如 `<a>` 默认具有这种行为，它们不需要该属性）。 |
| 正值（如 `tabindex="33"`） | 是 | `tabindex` 值决定了该元素在制表符顺序中的位置：值越小，元素在制表符顺序中的位置就越靠前（例如，`tabindex="7"` 将位于 `tabindex="11"` 之前）。 |

### 非原生控件

具有交互功能的原生 HTML 元素，如 `<a>`、`<input>` 和 `<select>`，已经可以被键盘访问，因此使用其中之一是让组件与键盘配合使用的最快途径。

作者还可以为 `<div>` 或 `<span>` 添加为 `0` 的 `tabindex` 值，使其可以通过键盘访问。这对于使用 HTML 中不存在的交互式元素的组件尤其有用。

### 组合控件

对于菜单、选项卡列表、网格或树状视图等组合微件，父元素应处于选项卡顺序中（`tabindex="0"`），而每个子选项/选项卡/单元格/行都应从选项卡顺序中移除（`tabindex="-1"`）。用户应能使用箭头键浏览后代元素。（有关典型窗口微件通常需要的键盘支持的完整描述，请参阅 WAI-ARIA 创作实践）。

下面的示例展示了这种技术在嵌套菜单控件中的应用。一旦键盘焦点落在包含 `<ul>` 的元素上，JavaScript 开发人员就必须以编程方式管理焦点并响应箭头键。有关在微件内管理焦点的技术，请参阅下面的“在组内管理焦点”。

```html
<ul id="mb1" tabindex="0">
  <li id="mb1\_menu1" tabindex="-1">
    Font
    <ul id="fontMenu" title="Font" tabindex="-1">
      <li id="sans-serif" tabindex="-1">Sans-serif</li>
      <li id="serif" tabindex="-1">Serif</li>
      <li id="monospace" tabindex="-1">Monospace</li>
      <li id="fantasy" tabindex="-1">Fantasy</li>
    </ul>
  </li>
  <li id="mb1\_menu2" tabindex="-1">
    Style
    <ul id="styleMenu" title="Style" tabindex="-1">
      <li id="italic" tabindex="-1">Italics</li>
      <li id="bold" tabindex="-1">Bold</li>
      <li id="underline" tabindex="-1">Underlined</li>
    </ul>
  </li>
  <li id="mb1\_menu3" tabindex="-1">
    Justification
    <ul id="justificationMenu" title="Justification" tabindex="-1">
      <li id="left" tabindex="-1">Left</li>
      <li id="center" tabindex="-1">Centered</li>
      <li id="right" tabindex="-1">Right</li>
      <li id="justify" tabindex="-1">Justify</li>
    </ul>
  </li>
</ul>
```

#### 被禁用的控件

当一个自定义控件变成禁用（disabled）状态时，通过设置 `tabindex="-1"` 把它从 tab 序列里面移除。请注意，组合微件中禁用的项目（如菜单中的菜单项）仍可使用箭头键导航。

在组合控件里面管理焦点
-----------

当用户从一个微件 tab 离开之后聚焦回来，焦点应该回到离开之时正被聚焦的元素上，比如某个树节点或者网格单元。有两种办法完成这一点：

1. 流动 `tabindex`: 通过编程移动焦点
2. `aria-activedescendent`: 管理一个“虚拟”焦点
### 方法 1：流动 tabindex

在被聚焦的元素上设置 `tabindex` 为“0”，这样可以保证在用户在 tab 离开又返回后仍然选中组合微件中之前被选中的那项。注意在更改 `tabindex` 为“0”同时需要把之前选中过的那项设置 `tabindex="-1"`。这个方法包含在键盘事件里面通过程序移动焦点以及更改 `tabindex` 到当前焦点中的那项上。需要做以下几步：

在每个元素上绑定 key down 事件，当捕捉到控制移动到另外元素的方向键时：

1. 通过编码把 focus 应用到新元素上，
2. 更改被 focus 中元素上的 tabindex 为“0”，并且
3. 更改之前被 focus 中元素的 tabindex 为“-1”。

下面是一个使用这种技术的 WAI-ARIA 树视图示例。

### 提示

#### 用 element.focus() 来设置焦点

不要使用 `createEvent()`、`initEvent()` 和 `dispatchEvent()` 来将焦点事件发送到元素上。DOM 焦点事件仅被视为信息性事件：由系统在某物被聚焦后生成，但实际上并不用于设置焦点。请使用 `element.focus()` 代替。

#### 用 onfocus 来追踪当前焦点

不要认为所有的焦点变化都来自于键盘和鼠标事件：像屏幕阅读器之类的辅助技术可以设置焦点到任意一个可聚焦元素上。用 `onfocus` 和 `onblur` 来追踪焦点。

`onfocus` 和 `onblur` 现在可以在每个元素上使用。没有标准的 DOM 接口来获取当前文档的焦点，如果要跟踪焦点状态，可以使用 document.activeElement 来获取活动元素。还可以使用 document.hasFocus 来确定当前文档是否处于焦点状态。

### 方法 2：`aria-activedescendant`

这个办法包含绑定一个单独的事件句柄到容器窗口微件上，运用 `aria-activedescendent` 属性来追踪一个“虚拟”焦点。（关于 ARIA 更多的信息，查看无障碍的 Web 应用程序和微件概述。）

`aria-activedescendant` 属性标识当前具有虚拟焦点的后代元素的 ID。容器上的事件处理程序必须通过更新 `aria-activedescendant` 属性的值来响应按键和鼠标事件，并确保当前项目的样式适当（例如，使用边框或背景色）。

一般准则
----

### 使用 onkeydown 来捕获键盘事件，而不是 onkeypress 事件

IE 不会触发非字母数字键的 `keypress` 事件。使用 `onkeydown` 替代。

### 确保键盘和鼠标有相同的体验

为了确保不同输入设备的用户体验一致，键盘和鼠标事件处理程序在适当的情况下应该共享代码。例如，当用户使用方向键导航的时候，一些代码会更新相应元素的 `tabindex` 或风格，用鼠标点击也应该有同样的变化。

### 确保键盘可以激活元素

为确保键盘可用于激活元素，与鼠标事件绑定的处理程序也应与键盘事件绑定。例如，为确保 Enter 键能激活元素，如果有一个 `onclick="doSomething()"`，则应将 `doSomething()` 也绑定到按键事件： `onkeydown="return event.keyCode !== 13 || doSomething();"`。

### 始终用程序为 tabindex="-1" 的项和元素设置焦点样式

对于以编程方式接收焦点的项目，IE 不会自动绘制焦点轮廓。可以选择通过 `this.style.backgroundColor = "gray";` 更改背景颜色，或通过 `this.style.border = "1px dotted invert"` 添加点状边框。在点状边框的情况下，需要确保这些元素一开始就有一个不可见的 1px 边框，这样在应用边框样式时元素就不会变大（边框会占用空间，而 IE 并没有实现 CSS 的轮廓）。

### 阻止浏览器的按键事件处理

如果你用自己的微件处理按键事件，可以通过事件处理程序的返回值来阻止浏览器的缺省处理（例如，响应方向键的滚动）。如果你的事件处理程序返回 `false`，事件就不会传播到处理程序之外。

例如：

```html
<span tabindex="-1" onkeydown="return handleKeyDown();">…</span>
```

如果 `handleKeyDown()` 返回 `false`，将会结束事件处理，阻止浏览器继续处理按键行为。

### 不要依赖于按键重复的一致行为

非常不幸，`onkeydown` 重复或不重复执行取决于代码执行的浏览器和操作系统。


ARIA 状态及属性 - 无障碍

ARIA 状态及属性
==========

这个页面列出了 MDN 上讨论的所有 WAI-ARIA 属性的参考页面。

ARIA 属性用于修改无障碍树中定义的元素的状态和属性。

**备注：** ARIA 仅用于修改无障碍树，进而改变辅助技术向用户呈现内容的方式。ARIA 不会改变元素的功能或行为。当使用非语义化的 HTML 元素来实现其他功能时，你必须使用 JavaScript 来控制元素的实际行为、焦点以及 ARIA 状态。

ARIA 特性类别
---------

ARIA 的状态和属性（合称为“特性”）共有 4 类：

1. ### 小部件（widget）特性

    * `aria-autocomplete` (en-US)
    * `aria-checked` (en-US)
    * `aria-disabled` (en-US)
    * `aria-errormessage` (en-US)
    * `aria-expanded` (en-US)
    * `aria-haspopup` (en-US)
    * `aria-hidden`
    * `aria-invalid` (en-US)
    * `aria-label`
    * `aria-level` (en-US)
    * `aria-modal` (en-US)
    * `aria-multiline` (en-US)
    * `aria-multiselectable` (en-US)
    * `aria-orientation` (en-US)
    * `aria-placeholder` (en-US)
    * `aria-pressed` (en-US)
    * `aria-readonly` (en-US)
    * `aria-required` (en-US)
    * `aria-selected` (en-US)
    * `aria-sort` (en-US)
    * `aria-valuemax` (en-US)
    * `aria-valuemin` (en-US)
    * `aria-valuenow` (en-US)
    * `aria-valuetext` (en-US)
2. ### 活动区域特性

    * `aria-busy` (en-US)
    * `aria-live` (en-US)
    * `aria-relevant` (en-US)
    * `aria-atomic` (en-US)
3. ### 拖放特性

    * `aria-dropeffect` (en-US)
    * `aria-grabbed` (en-US)
4. ### 关系特性

    * `aria-activedescendant` (en-US)
    * `aria-colcount` (en-US)
    * `aria-colindex` (en-US)
    * `aria-colspan` (en-US)
    * `aria-controls` (en-US)
    * `aria-describedby` (en-US)
    * `aria-description` (en-US)
    * `aria-details` (en-US)
    * `aria-errormessage` (en-US)
    * `aria-flowto` (en-US)
    * `aria-labelledby`
    * `aria-owns` (en-US)
    * `aria-posinset` (en-US)
    * `aria-rowcount` (en-US)
    * `aria-rowindex` (en-US)
    * `aria-rowspan` (en-US)
    * `aria-setsize` (en-US)
全局 ARIA 特性
----------

无论是否应用了 ARIA 角色，某些状态和属性始终适用于所有的 HTML 元素。它们被定义为“全局”特性。所有角色和基本标记元素都支持全局状态和属性。

上面所列出的许多特性都是全局的，这意味着除非被“特别禁止”，它们可以被包含在任意的元素中：

* `aria-atomic` (en-US)
* `aria-busy` (en-US)
* `aria-controls` (en-US)
* `aria-current` (en-US)
* `aria-describedby` (en-US)
* `aria-description` (en-US)
* `aria-details` (en-US)
* `aria-disabled` (en-US)
* `aria-dropeffect` (en-US)
* `aria-errormessage` (en-US)
* `aria-flowto` (en-US)
* `aria-grabbed` (en-US)
* `aria-haspopup` (en-US)
* `aria-hidden`
* `aria-invalid` (en-US)
* `aria-keyshortcuts` (en-US)
* `aria-label`
* `aria-labelledby`
* `aria-live` (en-US)
* `aria-owns` (en-US)
* `aria-relevant` (en-US)
* `aria-roledescription` (en-US)

除了 `aria-label` 和 `aria-labelledby` 这两个被“特别禁止”的属性，其他属性是全局适用的。这两个被“特别禁止”的属性无法在具有 `presentation` (en-US) 角色或与其同义的 `none` (en-US) 角色的元素上使用。

MDN 上介绍的状态和属性
-------------

以下是 MDN 上介绍的 WAI-ARIA 状态和属性。

Using the aria-labelledby attribute`aria-labelledby`属性用来表明某些元素的 id 是某一对象的标签。它被用来确定控件或控件组与它们标签之间的联系。使用诸如屏幕阅读器等辅助技术的用户通常使用 tabbing 在页面的不同区域间进行导航。如果一个输入元素、控件或控件组没有被分配一个 label 标签，那么屏幕阅读器就无法对其进行阅读。

使用 aria-hidden 属性本文用来说明如何使用 aria-hidden 属性。aria-hidden 属性可以用来控制一系列可访问 API 中的非交互内容的显示或隐藏。

使用 aria-label 属性aria-label 属性用来给当前元素加上的标签描述，接受字符串作为参数。是用不可视的方式给元素加 label（如果被描述元素存在真实的描述元素，可使用 aria-labelledby 属性作为来绑定描述元素和被描述元素来代替）。

参见
--

* 使用 ARIA：角色、状态和属性


ARIA live regions - 无障碍

ARIA live regions
=================

使用 JavaScript，我们可以动态更改页面的某些部分，而无需重新加载整个页面——例如，可以动态更新搜索结果列表，或者显示不需要用户交互的警告或通知。虽然这些更改对于能够看到页面的用户来说通常是显而易见的，但是对于残疾用户来说，它们可能并不明显。ARIA Live 区域填补了这个空白，并提供了一种以编程方式显现动态内容更改的方法，这种方式可以由残疾辅助技术提供提示。

**备注：** 辅助技术将播报实时区域内容的动态变化。必须首先显示活动区域（通常是空的），以便浏览器和辅助技术可以知道它。然后宣布任何后续更改。

在页面加载时的初始标记中简单地添加一个 `aria-live` 属性或者一个特殊的活动区域角色 ( `role` ) (例如 `role="alert"`) 将不会起作用。

向文档中动态添加一个包含 `aria-live` 属性的元素或者特殊的角色 ( `role` ) 也不会导致辅助技术工具的任何播报（在那个时间点，浏览器/辅助技术工具还没有检测到活动区域）所以你不能监控它的变化)。

总是确保实时区域首先出现在文档中，然后再动态添加/更改任何内容。

只要在更改发生之前添加属性，就可以在要宣布更改的元素上包含 `aria-live` 属性或专门的活动区域角色（例如`role =“ alert”`）——在原始标记中或动态地使用 JavaScript。

简单的活动区域
-------

在不重新加载页面的情况下更新的动态内容通常是区域或窗口小部件。非交互式的简单内容更改应标记为实时区域。以下是每个相关的 ARIA 活动区域属性的列表，并带有说明。

1. **`aria-live`**: `aria-live=POLITENESS_SETTING` 被用来设置屏幕阅读器对待活动区域更新的优先级 - 可能的设置：`off`, `polite` or `assertive` 。默认设置是 `off` 。这个设置是到目前为止最重要的。
2. **`aria-controls`**: `aria-controls=[IDLIST]` 被用来将控制动作与它控制的区域相关联。区域就像`div` 里面的 `id` 被鉴别；多区域可以被一个带空格的控制动作关联，例如： `aria-controls="myRegionID1 myRegionsID2"` 。

**警告：** 尚不知道在当前的辅助技术工具中是否实现了实时区域的 ARIA 控制方面。需要研究。

正常来说，只有 `aria-live="polite"` 被使用。任何对用户来说很重要但又不至于令人讨厌的更新的区域都应该被设置此属性。每当用户空闲时，屏幕阅读器都会说出更改。

对于不重要的区域或由于快速更新或其他原因而烦人的区域，请使用 `aria-live="off"` 将其静音。

### 让下拉框更新有用的屏幕信息

一个专门提供有关行星信息的网站提供了一个下拉框。从下拉列表中选择一个行星时，页面上的区域会更新有关所选行星的信息。

#### HTML

```html
<fieldset>
  <legend>Planet information</legend>
  <label for="planetsSelect">Planet:</label>
  <select id="planetsSelect" aria-controls="planetInfo">
    <option value="">Select a planet…</option>
    <option value="mercury">Mercury</option>
    <option value="venus">Venus</option>
    <option value="earth">Earth</option>
    <option value="mars">Mars</option>
  </select>
  <button id="renderPlanetInfoButton">Go</button>
</fieldset>

<div role="region" id="planetInfo" aria-live="polite">
  <h2 id="planetTitle">No planet selected</h2>
  <p id="planetDescription">Select a planet to view its description</p>
</div>

<p>
  <small
 >Information courtesy
    <a href="https://en.wikipedia.org/wiki/Solar\_System#Inner\_Solar\_System"
 >Wikipedia</a
 ></small
 >
</p>
```

#### JavaScript

```js
const PLANETS\_INFO = {
  mercury: {
    title: "Mercury",
    description:
      "Mercury is the smallest and innermost planet in the Solar System. It is named after the Roman deity Mercury, the messenger to the gods.",
  },

  venus: {
    title: "Venus",
    description:
      "Venus is the second planet from the Sun. It is named after the Roman goddess of love and beauty.",
  },

  earth: {
    title: "Earth",
    description:
      "Earth is the third planet from the Sun and the only object in the Universe known to harbor life.",
  },

  mars: {
    title: "Mars",
    description:
      'Mars is the fourth planet from the Sun and the second-smallest planet in the Solar System after Mercury. In English, Mars carries a name of the Roman god of war, and is often referred to as the "Red Planet".',
  },
};

function renderPlanetInfo(planet) {
  const planetTitle = document.querySelector("#planetTitle");
  const planetDescription = document.querySelector("#planetDescription");

  if (planet in PLANETS\_INFO) {
    planetTitle.textContent = PLANETS\_INFO[planet].title;
    planetDescription.textContent = PLANETS\_INFO[planet].description;
  } else {
    planetTitle.textContent = "No planet selected";
    planetDescription.textContent = "Select a planet to view its description";
  }
}

const renderPlanetInfoButton = document.querySelector(
  "#renderPlanetInfoButton",
);

renderPlanetInfoButton.addEventListener("click", (event) => {
  const planetsSelect = document.querySelector("#planetsSelect");
  const selectedPlanet =
    planetsSelect.options[planetsSelect.selectedIndex].value;

  renderPlanetInfo(selectedPlanet);
});
```

当用户选择一个新的行星时，活动区域的信息会被播报。因为这个活动区域有 `aria-live="polite"` 属性，屏幕阅读器将会等待用户暂停后再播报更新。这样的话，在列表中向下滑动并选择其他星球将不会在实时区域中播报更新。仅会针对最终选择的星球播报实时区域的更新。

这是 Mac 上 VoiceOver 的屏幕截图，播报对实时区域的更新（通过字幕）：
 ![A screenshot of VoiceOver on Mac announcing the update to a live region. Subtitles are shown in the picture.](/zh-CN/docs/Web/Accessibility/ARIA/ARIA_Live_Regions/web_accessibility_aria_aria_live_regions.png)

更好的专业活动区域角色
-----------

在以下众所周知的预定义情况下，最好使用提供的特定“活动区域角色”：

| 角色 | 描述 | 兼容性提示 |
| --- | --- | --- |
| 日志 | 对话、错误、游戏或者其他类型的日志 | 为最大化兼容性，当你使用这个角色时，请加入额外的`aria-live="polite"` 参数。 |
| 状态 | 一个状态栏或者屏幕上提供持续更新某种状态的区域。屏幕阅读器用户有一个特殊的命令用来读取当前的状态。 | 为最大化兼容性，当你使用这个角色时，请加入额外的`aria-live="polite"` 参数。 |
| 警告 | 在屏幕上闪烁的错误或警告信息。警报对于向用户发出客户端验证通知特别重要。（待定：带有 ARIA 信息的 ARIA 表单教程链接） | 为最大化兼容性，当你使用这个角色时，请加入额外的`aria-live="assertive"` 参数。但是，同时添加 `aria-live` 和 `role="alert"` 会导致在 iOS 平台上出现 VoiceOver 的双重播报问题。 |
| 进度条 | 小部件和活动区域之间的混合体。将此参数与 `aria-valuemin` ， `aria-valuenow` 和`aria-valuemax` 结合使用。（*待定*：请在此处添加更多信息）。 |  |
| 选框 | 用于滚动文本，例如股票行情自动收录器。 |  |
| 计时器 | 或任何类型的计时器或时钟，例如倒数计时器或秒表读数。 |  |

高级活动区域
------

（*待定*：有关操作系统 / 浏览器 / 辅助技术工具组合对单个属性的支持的更详细的信息）

JAWS 10.0 版中已添加对实时区域的常规支持。Windows Eyes 从 8.0 版开始支持“在 Microsoft Internet Explorer 和 Mozilla Firefox 的浏览模式之外使用”的实时区域。NVDA 早在 2008 年就为 Mozilla Firefox 添加了对实时区域的一些基本支持，并在 2010 年和 2014 年进行了改进。2015 年，还为 Internet Explorer（MSHTML）添加了基本支持。

Paciello Group 有一些 与活动区域支持状态有关的信息(2014)，Paul J. Adam 特别研究了对于 `Aria-Atomic` 与 `Aria-Relevant` 的支持。

1. **`aria-atomic`**: `aria-atomic=BOOLEAN` 被用来设置屏幕阅读器是否应该总是将活动区域整个播报，即使区域中只有一部分内容改变。可能的值为 `false` 或者 `true`。默认值为 `false`。
2. **`aria-relevant`**：`aria-relevant=[LIST_OF_CHANGES]` 被用来设置哪些类型的改变与活动区域有关。可能的值由以下的一个或者更多组成：`additions`、`removals`、`text`、`all`。默认值是 `additions text`。
3. **`aria-labelledby`** : `aria-labelledby=[IDLIST]` 被用来将一个区域与其标签关联起来，与 aria-control 类似，但将标签与区域关联。标签标识符间用空格隔开。
4. **`aria-describedby`** : `aria-describedby=[IDLIST]` 被用来将一个区域与其描述关联起来，与 aria-control 类似，但将标签与描述关联。描述标识符间用空格隔开。
### 高级用例：时钟

为了举例说明 `aria-atomic` ，请考虑一个带有简单时钟的站点，其中显示了小时和分钟。时钟每分钟更新一次，而新的剩余时间仅会覆盖当前内容。

```html
<div id="clock" role="timer" aria-live="polite"></div>
```

```js
/\* basic JavaScript to update the clock \*/

setInterval(function () {
  var now = new Date();
  document.getElementById("clock").innerHTML =
    "Time: " + now.getHours() + ":" + ("0" + now.getMinutes()).substr(-2);
}, 60000);
```

该函数第一次执行时，将播报所添加字符串的全部。在随后的调用中，将仅播报内容与先前内容相比已更改的部分。例如，当时钟从“17:33”更改为“17:34”时，辅助技术工具将仅播报“4”，这对用户不是很有用。

解决此问题的一种方法是，首先清除活动区域的内容，然后注入新内容。但是，有时这可能不可靠，因为这取决于这两个更新的确切时间。

`aria-atomic="true"` 确保每次更新实时区域时，全部内容都会被完整播报 (例如 "时间：17:34").

```html
<div id="clock" role="timer" aria-live="polite" aria-atomic="true"></div>
```

**备注：** 正如我们观察到的那样，重新设置/更新 innerHTML 会导致整个文本被重新播报，无论你是否设置 `aria-atomic="true"` ，所以以上的时钟示例并不能像预期那样地工作。

一个简单的年份控件的工作示例，可以帮助你更好地理解：

```html
<div id="date-input">
  <label
 >Year:
    <input type="text" id="year" value="1990" onblur="change(event)" />
  </label>
</div>

<div id="date-output" aria-live="polite">
  The set year is:
  <span id="year-output">1990</span>
</div>
```

```js
function change(event) {
  var yearOut = document.getElementById("year-output");
  switch (event.target.id) {
    case "year":
      yearOut.innerHTML = event.target.value;
      break;
    default:
      return;
  }
}
```

如果没有 `aria-atomic="true"` ，屏幕阅读器只会播报"年"的数值的改变。

如果有 `aria-atomic-="true"` ，屏幕阅读器会播报"设置的年为：*改变的值*"。

### 高级用例：名册

一个聊天站点想要显示当前登录用户的列表。列表将动态反映用户的登录和注销状态的用户（无需重新加载页面）。

```html
<ul id="roster" aria-live="polite" aria-relevant="additions removals">
  <!-- use JavaScript to add remove users here-->
</ul>
```

ARIA 活动属性的细分：

* `aria-live="polite"` 指示屏幕阅读器应该等到用户空闲后再播报更新。这是最常用的值，因为用 `“assertive”` 值会打扰用户，打断他们的操作流程。
* `aria-atomic` 没有设置 (默认为 `false` ) ，这样就只能说出添加或删除的用户，而不是整个名单。
* `aria-relevant="additions removals"` 确保在在线名册中添加用户与移除用户的时候都会被播报。
参考
--

* ARIA 角色


WAI-ARIA 角色 - 无障碍

WAI-ARIA 角色
===========

ARIA 角色为内容提供了语义，允许屏幕阅读器和其他工具与对象类型的用户预期一致的方式进行呈现并支持交互。ARIA 角色可以用于描述不在 HTML 中原生存在的元素，或者存在但没有完整的浏览器支持的元素。

默认情况下，很多语义的 HTML 元素都有角色，例如，`<input type="radio">` 有“radio”角色。HTML 的非语义的元素没有角色，例如没有添加语义的 `<div>` 和 `<span>` 会返回 `null`。`role` 属性可以添加语义。

将 ARIA 角色添加到 HTML 元素的方法是使用 `role="角色类型"`，其中*角色类型*是角色在 ARIA 规范中的名称。有些角色需要包含相关的状态或属性；其他这些仅在与其他角色关联时有用。

例如，`<ul role="tabpanel">` 会被屏幕阅读器读作“标签面板（tab panel）”。但是，如果标签页面没有嵌套的标签，带有标签页面角色的元素实际上并不是个标签面板，从而对无障碍造成负面影响。

各角色的页面中都包含了相关的 ARIA 状态和属性，而每个属性都有一个专门的页面。

ARIA 角色类型
---------

ARIA 角色共分为 6 类：

### 1. 文档结构角色

文档结构角色用于给内容的段落添加一个结构的描述。这些角色大多数都不应该再使用，因为浏览器现在支持带有相同的含义的语义化 HTML 元素。没有相应 HTML 等价的角色，例如 presentation、toolbar 和 tooltip 角色，为辅助技术（例如屏幕阅读器）提供了文档结构信息，而这些信息没有可用的原生 HTML。

* toolbar (en-US)
* tooltip (en-US)
* feed (en-US)
* math (en-US)
* presentation (en-US) / none (en-US)
* note (en-US)

对于大多数结构角色，都有可用、受支持且等价的语义化 HTML 元素。请避免使用：

* application (en-US)
* article (en-US)（请使用 `<article>`）
* cell (en-US)（请使用 `<td>` (en-US)）
* columnheader (en-US)（请使用 `<th scope="col">`）
* definition (en-US)（请使用 `<dfn>`）
* directory (en-US)
* document (en-US)
* figure (en-US)（请使用 `<figure>`）
* group (en-US)
* heading (en-US)（请使用 h1 到 h6）
* img (en-US)（请使用 `<img>` 或 `<picture>`）
* list（请使用 `<ul>` 或 `<ol>`）
* listitem（请使用 `<li>`）
* meter (en-US)（请使用 `<meter>`）
* row (en-US)（请使用 `<tr>` 和 `<table>`）
* rowgroup (en-US)（请使用 `<thead>`、`<tfoot>` 和 `<tbody>`）
* rowheader (en-US)（请使用 `<th scope="row">`）
* separator (en-US)（如果不可以聚焦，请使用 `<hr>`）
* table (en-US)（请使用 `<table>`）
* term (en-US)（请使用 `<dfn>`）

这些内容是为保持完整而包含的，但至今很少使用或有用：

* `associationlist` (en-US)
* `associationlistitemkey` (en-US)
* `associationlistitemvalue` (en-US)
* `blockquote` (en-US)
* `caption` (en-US)
* `code` (en-US)
* `deletion` (en-US)
* `emphasis` (en-US)
* `insertion` (en-US)
* `paragraph` (en-US)
* `strong` (en-US)
* `subscript` (en-US)
* `superscript` (en-US)
* `time` (en-US)
### 2. 小部件角色

各种小部件角色用于定义常见的交互模式。类似于文档结构角色，有些这些角色与同样受支持的原生 HTML 的语义是重复的，因此不应该使用。这两个列表的区别在于，通常来说，小部件角色需要 JavaScript 交互，而文档结构角色不需要。

* scrollbar (en-US)
* searchbox (en-US)
* separator (en-US)（如果可以聚焦）
* slider (en-US)
* spinbutton (en-US)
* switch (en-US)
* tab (en-US)
* tabpanel (en-US)
* treeitem (en-US)

避免使用 button、checkbox (en-US)、gridcell (en-US)、link (en-US)、menuitem (en-US)、menuitemcheckbox (en-US)、menuitemradio (en-US)、option (en-US)、progressbar (en-US)、radio (en-US)和 textbox (en-US)，这些仅为完整性而包含。大多数情况下，带有无障碍的交互性的语义等价也是可用且受支持的。更多信息，请参见其各个角色的文档。

#### 复合小部件角色

* combobox (en-US)
* menu (en-US)
* menubar (en-US)
* tablist (en-US)
* tree (en-US)
* treegrid (en-US)

避免使用 grid (en-US)、listbox 和 radiogroup (en-US)，这些仅为完整性而包含。更多信息，请参见其各个角色的文档。

注意还有个 widget 角色（`role="widget"`），这是个抽象的角色，不在小部件角色类别中。

### 3. 地标角色

地标（landmark）角色提供了一种识别网页的组织和结构的方法。对页面的各个部分进行分类并添加标签，可以用编程方式呈现出通过布局直观传达的结构信息。屏幕阅读器使用地标角色为页面的重要部分提供键盘导航。谨慎使用这些。太多的地标角色会在屏幕阅读器中产生“噪音”，导致难以理解页面的整体布局。

* banner (en-US) （文档 `<header>`）
* complementary (en-US)（`<aside>`）
* contentinfo (en-US)（`<footer>`）
* form (en-US)（`<form>`）
* main (en-US)（`<main>`）
* navigation (en-US)（`<nav>`）
* region (en-US)（`<section>`）
* search (en-US)
### 4. 实时区域角色

实时区域（Live Region）角色用于定义带有动态更改的内容的元素。动态变化在视觉上明显时，具有视力的的用户可以看到。这些角色可帮助低视力和盲人用户了解内容是否更新。辅助技术，例如屏幕阅读器，可以告知动态内容变更：

* alert (en-US)
* log (en-US)
* marquee (en-US)
* status (en-US)
* timer (en-US)
### 5. 窗口角色

窗口角色为同一文档内的主文档窗口定义了子窗口，例如弹出模态框：

* alertdialog (en-US)
* dialog (en-US)
### 6. 抽象角色

抽象角色仅由浏览器使用，以帮助组织和简化文档。编写 HTML 标记的开发者不应使用这些抽象角色。这样做不会向辅助技术或用户传达任何有意义的信息。

避免使用command (en-US)、composite (en-US)、input (en-US)、landmark (en-US)、range (en-US)、roletype (en-US)、section (en-US)、sectionhead (en-US)、select (en-US)、structure (en-US)、widget (en-US) 和 window (en-US)。

**备注：** 不要在你的网站和应用中使用抽象角色。抽象角色是由浏览器使用的，这里列出来仅用于参考。

**警告：**“抽象角色用于本体。作者**不得**在内容中使用抽象角色。”——WAI-ARIA 规范

MDN 中定义的角色
----------

以下是包含 MDN 中讨论的 WAI-ARIA 角色的参考页面。

ARIA：button 角色`button` 角色用于可单击的元素，在用户激活时触发响应。添加 `role="button"` 会告诉屏幕阅读器这个元素是个按钮，但是不提供按钮的功能。你应该使用的 `button` 或者 `type="button"` 的 `input`。

ARIA：list 角色ARIA `list` 角色可用于标识项目列表。它通常与 `listitem` 角色结合使用，该角色用于标识包含在列表中的列表项。

ARIA：listbox 角色`listbox` 角色用于列表，用户可以从中选择一个或多个静态选项，并且与 HTML `select` 元素不同，它可能包含图像。

ARIA：listitem 角色ARIA `listitem` 角色可用于标识项目列表中的项目。它通常与 `list` 角色（用于标识列表容器）结合使用。

参见
--

* 使用 ARIA：角色、状态和属性
* ARIA 状态和属性


使用 ARIA：角色、状态和属性 - 无障碍

使用 ARIA：角色、状态和属性
================

ARIA 定义了可以应用于元素的语义，这些语义分为 **roles**（定义一种用户界面元素）、**states** 和 **properties**，这些都是角色所支持的。作者必须在元素的生命周期中为其分配一个 ARIA 角色和适当的状态和属性，除非该元素已经具有适当的 ARIA 语义（通过使用适当的 HTML 元素）。添加 ARIA 语义只会向浏览器的无障碍 API 公开额外信息，而不会影响页面的 DOM。

角色
--

### 组件角色

* button
* checkbox (en-US)
* gridcell (en-US)
* link (en-US)
* menuitem
* menuitemcheckbox
* menuitemradio
* option
* progressbar (en-US)
* radio (en-US)
* scrollbar
* searchbox
* separator (when focusable)
* slider (en-US)
* spinbutton
* switch (en-US)
* tab (en-US)
* tabpanel (en-US)
* textbox (en-US)
* treeitem
### 复合角色

下面的技术描述了每个复合角色及其必需和可选的子角色。

* combobox
* grid (en-US) (包含 row (en-US), gridcell (en-US), rowheader, columnheader)
* listbox (包含 option)
* menu
* menubar
* radiogroup (en-US) (参考 radio)
* tablist (包含 tab (en-US) 和 tabpanel (en-US))
* tree
* treegrid
### 文档结构角色

* application (en-US)
* article (en-US)
* cell (en-US)
* columnheader
* definition
* directory
* document (en-US)
* feed
* figure (en-US)
* group (en-US)
* heading (en-US)
* img
* list
* listitem
* math
* none
* note
* presentation (en-US)
* row (en-US)
* rowgroup (en-US)
* rowheader
* separator
* table (en-US)
* term
* toolbar (en-US)
* tooltip
### 具有里程碑意义的角色

* banner (en-US)
* complementary (en-US)
* contentinfo (en-US)
* form (en-US)
* main (en-US)
* navigation (en-US)
* region (en-US)
* search (en-US)
### 实时区域角色

* alert (en-US)
* log (en-US)
* marquee
* status (en-US)
* timer (en-US)
### 窗口角色

* alertdialog (en-US)
* dialog (en-US)
状态和属性
-----

### 组件属性

* aria-autocomplete
* aria-checked
* aria-current
* aria-disabled
* aria-errormessage
* aria-expanded
* aria-haspopup
* aria-hidden
* aria-invalid
* aria-label
* aria-level
* aria-modal
* aria-multiline
* aria-multiselectable
* aria-orientation
* aria-placeholder
* aria-pressed
* aria-readonly
* aria-required
* aria-selected
* aria-sort
* aria-valuemax
* aria-valuemin
* aria-valuenow
* aria-valuetext
### 实时区域属性

* aria-live
* aria-relevant
* aria-atomic
* aria-busy
### 拖放属性

* aria-dropeffect
* aria-dragged
### 关系属性

* aria-activedescendant (en-US)
* aria-colcount
* aria-colindex
* aria-colspan
* aria-controls
* aria-describedby
* aria-details (en-US)
* aria-errormessage
* aria-flowto
* aria-labelledby
* aria-owns
* aria-posinset
* aria-rowcount
* aria-rowindex
* aria-rowspan
* aria-setsize
### MicrosoftEdge 特定的属性

* x-ms-aria-flowfrom (en-US)
非标准


Using the aria-labelledby attribute - 无障碍

Using the aria-labelledby attribute
===================================

### 描述

`aria-labelledby`属性用来表明某些元素的 id 是某一对象的标签。它被用来确定控件或控件组与它们标签之间的联系。使用诸如屏幕阅读器等辅助技术的用户通常使用 tabbing 在页面的不同区域间进行导航。如果一个输入元素、控件或控件组没有被分配一个 label 标签，那么屏幕阅读器就无法对其进行阅读。

`aria-labelledby` 属性与aria-describedby属性非常相似：用一个标签描述某一对象的本质，可能会提供一些用户需要了解的额外信息。

`aria-labelledby` 属性并不仅仅用于表单元素，也可以用来分配静态文本给控件、元素组、面板组以及包含标题和定义等内容的区域等。下方的示例将会展示如何针对这些情况运用这一属性的更多信息。

`aria-labelledby` 属性可以与 HTML 元素 label 联合使用，用于提高对于不支持 ARIA 技术的用户代理的兼容性。

这一属性可以用于任何典型的 HTML 表单元素，不仅限于已分配 ARIA role 的元素。

### 值 Value

一个以空格进行分割的元素 ID 列表。

### 对于用户代理和辅助技术的可能影响

当 `aria-labelledby` 和 `aria-label` 都被使用时，用户代理在生成可访问的名称属性时将为 `aria-labelledby` 分配更高的优先级。

**注意：** 由于不同的辅助技术对于这一技术的处理可能不同，以上提供的信息尽是诸多可能的一种，而非一般情况。

### 示例

#### 示例 1: 多标签 Mutiple Labels

在下面的示例中，每个输入域都被它自身的独立标签以及其所在组的标签进行了标识：

```html
<div id="billing">Billing Address</div>

<div>
  <div id="name">Name</div>
  <input type="text" aria-labelledby="name billing" />
</div>
<div>
  <div id="address">Address</div>
  <input type="text" aria-labelledby="address billing" />
</div>
```

#### 示例 2: 联结的标题和区域 Associating Headings With Regions

在下面的示例中，标题元素被与它们作为标题的内容联结在一起。注意，所参考的区域是包含标题元素的那个区域。

```html
<div role="main" aria-labelledby="foo">
  <h1 id="foo">Wild fires spread across the San Diego Hills</h1>
  Strong winds expand fires ignited by high temperatures ...
</div>
```

#### 示例 3: 单选组 Radio Groups

在下面的示例中，单选组radiogroup的容器通过一个 aria-labeledby 属性与他的的标签相联结：

```html
<div id="radio\_label">My radio label</div>
<ul role="radiogroup" aria-labelledby="radio\_label">
  <li role="radio">Item #1</li>
  <li role="radio">Item #2</li>
  <li role="radio">Item #3</li>
</ul>
```

#### 示例 4: 对话框标签 Dialog Label

在下面的示例中，标记对话框的标题元素通过 aria-labeledby 属性被引用

```html
<div role="dialog" aria-labelledby="dialogheader">
  <h2 id="dialogheader">Choose a File</h2>
  ... Dialog contents
</div>
```

#### 示例 5: 内联定义 Inline Definition

在下面的示例中，某一事物的被一个叙述性的自然流所描述的定义与这一事物本身通过**aria-labeledby**属性相联结：

```html
<p>
  The doctor explained it had been a <dfn id="placebo">placebo</dfn>, or
  <span role="definition" aria-labelledby="placebo">
    an inert preparation prescribed more for the mental relief of the patient
    than for its actual effect on a disorder.</span
 >
</p>
```

#### 示例 6: 定义列表 Definition Lists

在下面的示例中，正式的定义列表中的定义与他们所定义的项目通过 aria-labeledby 属性相联结：

```html
<dl>
  <dt id="anathema">anthema</dt>
  <dd role="definition" aria-labelledby="anathema">
    a ban or curse solemnly pronounced by ecclesiastical authority and
    accompanied by excommunication
  </dd>
  <dd role="definition" aria-labelledby="anathema">
    a vigorous denunciation : cursor
  </dd>

  <dt id="homily">homily</dt>
  <dd role="definition" aria-labelledby="homily">a usually short sermon</dd>
  <dd role="definition" aria-labelledby="homily">
    a lecture or discourse on or of a moral theme
  </dd>
</dl>
```

#### 示例 7: 菜单

在下面的示例中，一个popup menu通过 aria-labeledby 属性与其标签相联结：

```html
<div role="menubar">
  <div role="menuitem" aria-haspopup="true" id="fileMenu">File</div>
  <div role="menu" aria-labelledby="fileMenu">
    <div role="menuitem">Open</div>
    <div role="menuitem">Save</div>
    <div role="menuitem">Save as ...</div>
    ...
  </div>
  ...
</div>
```

### 注意

The most common *accessibility API* mapping for a label is the *accessible name* property

### Used by ARIA roles

all elements of the base markup

### Related ARIA techniques

* Using the aria-label attribute
* Using the aria-describedby attribute
### Compatibility

TBD: Add support information for common UA and AT product combinations

### Additional resources

* WAI-ARIA specification for aria-labelledby


使用 aria-hidden 属性 - 无障碍

使用 aria-hidden 属性
=================

本文用来说明如何使用 aria-hidden 属性。aria-hidden 属性可以用来控制一系列可访问 API 中的非交互内容的显示或隐藏。

描述
--

把 `aria-hidden="true"` 加到元素上会把该元素和它的所有子元素从无障碍树上移除。这样做可以通过隐藏下列内容来提升使用辅助技术的用户体验：

* 纯装饰性的内容，如图标、图片
* 重复的内容，如重复的文本
* 屏幕外或被折叠的内容，如菜单

根据无障碍的第四条规则，`aria-hidden="true"` 不应该被用在可聚焦的元素上。而且，由于这个属性是可以被子元素继承的，它也不应该被用在可聚焦元素的父元素上。

如果父元素带有 `aria-hidden="true"` ，那么即使使用 `aria-hidden="false"` 也无法将该元素显示出来。

**警告：** WAI-ARIA Authoring Practices 1.1 提示 `aria-hidden="false"` 在现阶段 各个浏览器中表现不同.

### 比较 `aria-hidden="true"`， `role="presentation"` 和 `role="none"`

表面上，`aria-hidden="true"`，`role="presentation"`，和`role="none"` 很相似，因为这三者都有以下特性：

* 根据辅助即使隐藏页面内容
* 无法在可聚焦元素上使用
* 无法在可互动元素的父级元素上使用

尽管有上面这些相同点，但是各个属性的意图是不同的。

* `aria-hidden="true"` 会把整个元素从无障碍 API 中移除
* `role="presentation"` 和`role="none"` 会将元素从语义上移除，仍然会将元素暴露给辅助技术。
### 可选值

`false`

（默认）元素会暴露给无障碍 API。

`true`

元素不会暴露给无障碍 API。

`undefined`

（默认）客户端决定元素是否暴露给无障碍 API。

示例
--

```html
<i class="icon" aria-hidden="true" />
```

无障碍问题
-----

最佳实践
----

`aria-hidden="true"` 在以下场景不应该被使用：

* HTML 的`hidden`属性被设置了
* 祖先元素被`display: none`属性设置成不显示状态
* 祖先元素被`visibility: hidden`属性设置成不显示状态

在以上三个场景中，元素已经被隐藏，从可访问树种移除了，无需再添加`aria-hidden="true"`属性。

规范
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # aria-hidden |

另见
--

* 使用展示角色 (en-US)
* role="none"


使用 aria-label 属性 - 无障碍

使用 aria-label 属性
================

aria-label 属性用来给当前元素加上的标签描述，接受字符串作为参数。是用不可视的方式给元素加 label（如果被描述元素存在真实的描述元素，可使用 aria-labelledby 属性作为来绑定描述元素和被描述元素来代替）。

aria-label 属性可以用在任何典型的 HTML 元素中，并不需要配合特定的 ARIA role 才能使用。

### Value

string

### 对于用户代理和辅助技术的可能影响

**备注：** 由于辅助技术处理这一技术的差异导致选项信息可能不同。以上所提供的信息只是其中可能的一种，而非一般情况。

示例
--

#### 示例 1：多标签（Multiple Labels）

在下面的示例中，按钮（button）元素被定义为一个关闭（close）按钮，按钮中间有一个“X”字符。辅助软件并不能知道 X 是什么意思，所以需要 aria-label 标签来为辅助设备提供相应的标识来告诉它这个 button 是 close 的作用。

```html
<button aria-label="Close" onclick="myDialog.close()">X</button>
```

### 说明

最常见的对于标签的无障碍 API 就是可访问的 name 属性。

### ARIA roles 的使用

基本标记中的全部元素。

### ARIA 相关技术

* Using the aria-labelledby attribute
### 兼容性

有待讨论：为通常的 UA 和 AT 产品组合提供支持信息。

### 额外资源

* WAI-ARIA specification for aria-label


ARIA：button 角色 - 无障碍

ARIA：button 角色
==============

`button` 角色用于可单击的元素，在用户激活时触发响应。添加 `role="button"` 会告诉屏幕阅读器这个元素是个按钮，但是不提供按钮的功能。你应该使用的 `<button>` 或者 `type="button"` 的 `<input>`。

描述
--

button 角色会向辅助技术（如屏幕阅读器）识别一个元素为按钮。按钮是用于执行操作的小部件，例如提交表单、打开对话框、退出活动或执行一个命令，例如插入新的记录或者显示信息。添加 `role="button"` 会告诉辅助技术，这是一个按钮，但是不提供按钮的功能。你应该使用 `<button>` 或者 `<input>` 以及 `type="button"`。

`button` 角色可以和 `aria-pressed` (en-US) 属性一起使用，以创建切换按钮。

```html
<div id="saveChanges" tabindex="0" role="button" aria-pressed="false">保存</div>
```

上面这个例子创建了一个可聚焦的按钮，但是需要 JavaScript 和 CSS 来包含按钮的外观和行为。这些功能默认是由 `<button>` 或者 `<input>`（带有 `type="button"`）元素提供的。

```html
<button type="button" id="saveChanges">保存</button>
```

**备注：** 如果使用 `role="button"` 而不是语义化的 `<button>` 或 `<input type="button">` 你需要让这个元素可聚焦并定义 `click` 和 `keydown` 事件的事件处理器。这包括了对按下 `Enter` 和 `Space` 的事件的处理，以处理各种形式的用户输入。参见官方的 WAI-ARIA 示例代码。

除了常见的按钮部件之外，使用非按钮元素创建切换按钮和菜单按钮时，应该使用 `role="button"`。

切换按钮是指有两个状态的按钮，可以是关（未按下）或者开（已按下）。`aria-pressed` (en-US) 属性值 `true` 或 `false` 会将按钮识别为切换按钮。

菜单按钮是指控制一个菜单且 `aria-haspopup` (en-US) 属性设置为 `menu` 或 `true` 的按钮。

### 所有子元素都是仅作展示的

有些类型的用户界面元件，呈现在平台无障碍 API 中时，仅可包含文本。无障碍 API 没有呈现 `button` 中包含的语义元素的方式。要处理这个限制，浏览器会自动为任何 `button` 的后代元素应用角色 `presentation` (en-US)，因为按钮这种角色不支持带有语义的子元素。

例如，考虑以下包含标题的 `button` 元素。

```html
<div role="button"><h3>按钮的标题</h3></div>
```

由于 `button` 的子元素都是仅作展示的，因此相当于以下的代码：

```html
<div role="button"><h3 role="presentation">按钮的标题</h3></div>
```

从辅助技术的视角来看，这个标题不存在，因为前面的代码片段在无障碍树 (en-US)中相当于以下内容：

```html
<div role="button">按钮的标题</div>
```

### 关联的 ARIA 角色、状态和属性

`aria-pressed` (en-US)

`aria-pressed` 属性将按钮定义为切换按钮。此值描述了按钮的状态。值包括 `aria-pressed="false"`（按钮还没有被按下）、`aria-pressed="true"`（按钮当前已被按下）和 `aria-pressed="mixed"`（按钮被视为部分按下）。如果此属性被忽略，或者设置为默认值 `aria-pressed="undefined"`，那么元素不支持被按下。

`aria-expanded` (en-US)

如果按钮控制了其他元素的分组，`aria-expanded` 状态指示了被控制的分组当前是被展开还是折叠。如果按钮设置了 `aria-expanded="false"`，则分组当前未展开；如果按钮设置了 `aria-expanded="true"`，则分组当前已展开；如果按钮设置了 `aria-expanded="undefined"`，则其是不可展开的。

### 基本的按钮

按钮始终应该有无障碍的名称。对于大多数的按钮，名称通常是和按钮内的文本、开启和闭合标签之间的内容一致的。一些情况下，比如以图标形式呈现的按钮，其无障碍名称可能是由 `aria-label` 或者 `aria-labelledby` 属性提供的。

切换按钮
----

切换按钮通常有两种状态：按下、没有按下，第三种混合状态可用于控制了其他的元素的切换按钮，例如其他的不共享同一个值的切换按钮或者复选框。还可以使用 `button` 角色（如果元素不是原生的 button 元素）加 `aria-pressed` (en-US) 属性来表示元素是否为切换按钮：

* 如果没有 `aria-pressed`，说明这不是一个切换按钮。
* 如果 `aria-pressed="false"`，说明这个按钮当前没有被按下。
* 如果 `aria-pressed="true"`。说明这个按钮当前已被按下。
* 如果 `aria-pressed="mixed"`，说明这个按钮被认为是部分按下的。

比如，音频播放器上有“静音”标签的静音按钮应该表示当 `aria-pressed` 状态为 true 时声音是静音的。切换按钮的标签不应该随状态改变而改变。在这个例子中，当屏幕阅读器说“静音切换按钮已按下”或者“静音切换按钮未按下”（取决于 `aria-pressed` 时），按钮的标签都始终为“静音”。如果设计时是要让按钮标签由“静音”更改为“取消静音”，那么这时候切换按钮并不合适，`aria-pressed` 属性应该省略。

### 键盘交互

| 按键 | 功能 |
| --- | --- |
| `Enter` | 激活按钮。 |
| `Space` | 激活按钮。 |

按钮激活后，会根据按钮执行的操作的类型设置焦点。比如，如果点击打开对话框的按钮，那么焦点应该移动到对话框。如果按钮是关闭对话框的，那么焦点应该回到打开对话框的按钮，除非对话框上下文中执行的功能在逻辑上是导向到不同的元素的。如果按钮更改了当前的上下文，例如将音频文件静音或者取消静音，那么焦点通常应该留在按钮上。

### 必需的 JavaScript 特性

#### 必需的事件处理器

按钮可能是由鼠标、触屏或者键盘用户操作的。对于原生的 `<button>` 元素，按钮的 `onclick` 事件会在用户点击时，以及在按钮被聚焦且用户按下 `Space` 或 `Enter` 时触发。但如果使用其他标签创建按钮，那么 `onclick` 事件只会在用户使用鼠标指针点击时才会触发，即使使用了 `role="button"`。因此，需要给元素添加单独的事件处理器，以在按下 `Space` 或 `Enter` 键时触发按钮。

`onclick`

使用鼠标点击或者触摸事件激活按钮时产生的事件。

`onKeyDown`

使用键盘上的 Enter 或 Space 键激活按钮时触发的事件。（注意不是已弃用的 onKeyPress。）

示例
--

### 基本按钮示例

在这个例子中，span 元素有个 `button` 角色。由于使用了 `<span>` 元素，需要使用 `tabindex` 属性以使得按钮可聚焦，并成为页面的 tab 顺序的一部分。还有包含 CSS 样式，以使得这个 `<span>` 元素看上去像是个按钮，并在按钮被聚焦时，提供了视觉呈现。

`handleBtnClick` 和 `handleBtnKeyDown` 事件处理器执行了按钮在鼠标单击或者按下 `Space` 或 `Enter` 键的操作。在这个例子中，操作是给名字列表添加一个新的名字。

在文本框中添加名称以尝试这个例子。按钮会给列表添加一个新的名字。

#### HTML

```html
<h1>ARIA 按钮示例</h1>
<ul id="nameList"></ul>
<label for="newName">输入你的名字：</label>
<input type="text" id="newName" />
<span
 role="button"
 tabindex="0"
 onclick="handleCommand(event)"
 onKeyDown="handleCommand(event)"
 >添加名字</span
>
```

#### CSS

```css
[role="button"] {
  padding: 2px;
  background-color: navy;
  color: white;
  cursor: default;
}
[role="button"]:hover,
[role="button"]:focus,
[role="button"]:active {
  background-color: white;
  color: navy;
}
ul {
  list-style: none;
}
```

#### JavaScript

```js
function handleCommand(event) {
  // 处理鼠标单击以及 Enter 或 Space 的按键激活

  // 除 Enter 或 Space 之外的按键不应该触发命令
  if (
    event instanceof KeyboardEvent &&
    event.key !== "Enter" &&
    event.key !== " "
  ) {
    return;
  }

  // 从输入框中获取新的名字
  const newNameInput = document.getElementById("newName");
  const name = newNameInput.value;
  newNameInput.value = ""; // 清除文本框
  newNameInput.focus(); // 给予文本框焦点，以允许添加额外的名称。

  // 不要在列表中添加空白项。
  if (name.length > 0) {
    const listItem = document.createElement("li");
    listItem.appendChild(document.createTextNode(name));

    // 在列表中添加新的名字。
    const list = document.getElementById("nameList");
    list.appendChild(listItem);
  }
}
```

### 切换按钮示例

在这个片段中，使用 `button` 角色和 `aria-pressed` 属性，以将 `<span>` 元素转换为切换按钮，按钮被激活时，`aria-pressed` 的值在 `true` 和 `false` 之间切换。

#### HTML

```html
<button
 type="button"
 onclick="handleBtnClick(event)"
 onKeyDown="handleBtnKeyDown(event)">
  静音音频
</button>

<span
 role="button"
 tabindex="0"
 aria-pressed="false"
 onclick="handleBtnClick(event)"
 onKeyDown="handleBtnKeyDown(event)">
  静音音频
</span>

<audio
 id="audio"
 src="https://soundbible.com/mp3/Tyrannosaurus%20Rex%20Roar-SoundBible.com-807702404.mp3">
  你的浏览器不支持 `audio` 元素。
</audio>
```

#### CSS

```css
button,
[role="button"] {
  padding: 3px;
  border: 2px solid transparent;
}

button:active,
button:focus,
[role="button"][aria-pressed="true"] {
  border: 2px solid #000;
}
```

#### JavaScript

```js
function handleBtnClick(event) {
  toggleButton(event.target);
}

function handleBtnKeyDown(event) {
  // 检查 space 或 enter 是否已按下
  // "Spacebar" 是为 IE11 支持
  if (event.key === " " || event.key === "Enter" || event.key === "Spacebar") {
    // 避免按下空格键时滚动屏幕的默认操作
    event.preventDefault();
    toggleButton(event.target);
  }
}

function toggleButton(element) {
  const audio = document.getElementById("audio");

  // 检查按钮是否已按下
  const pressed = element.getAttribute("aria-pressed") === "true";

  // 将 aria-pressed 设为相反的状态
  element.setAttribute("aria-pressed", !pressed);

  // 切换音频文件的播放状态
  if (pressed) {
    audio.pause();
  } else {
    audio.play();
  }
}
```

### 结果

无障碍考虑
-----

按钮本身是可交互的，因此可聚焦。如果给自身不可聚焦的元素（如 `<span>`、`<div>` 或 `<p>`）添加了 `button` 角色，那么就应该使用 `tabindex` 属性以使得按钮可聚焦。

**警告：** 谨慎将链接标记为按钮。按钮是预期使用 `Space` 或 `Enter` 键触发的，而链接是预期使用 `Enter` 触发的。也就是说，如果将链接用作按钮，仅添加 `role="button"` 是不够的。还有必要为 `Space` 键添加一个按键事件处理器，以与原生按钮的行为保持一致。

使用了 `button` 角色时，屏幕阅读器会声明其说成是一个按钮，通常是说“单击（click）”然后是其无障碍名称。无障碍名称是元素的内容，或是 `aria-label` 的值，或是由 `aria-labelledby` 属性引用的元素的值，或是描述（如果已包括）。

最佳实践
----

如果链接执行的是按钮的操作，那么为元素设置 `role="button"` 可以帮助辅助技术用户理解这个元素的功能。然而，更好的设计是调整视觉设计从而匹配其功能和 ARIA 角色。如果可能，建议使用原生的 HTML 按钮（`<button>`、`<input type="button">`、`<input type="submit">`、`<input type="reset">` 和 `<input type="image">`）而不是 `button` 角色，因为原生 HTML 按钮能够被所有的用户代理和辅助技术所支持，且默认会提供键盘和聚焦需求而不需要额外的自定义。

规范
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # button |
| Unknown specification  |

参见
--

* `<button>` 元素
* `<input>` 元素
* `<input type="button">`
* `<input type="submit">`
* `<input type="reset">`
* `aria-pressed`
* `aria-expanded`
* `aria-haspopup`
* HTML5 中强大的原生语义
* 在 HTML 中使用 ARIA 的注意事项
* 官方 WAI-ARIA 示例代码


ARIA：listitem 角色 - 无障碍

ARIA：listitem 角色
================

ARIA `listitem` 角色可用于标识项目列表中的项目。它通常与 `list` 角色（用于标识列表容器）结合使用。

```html
<section role="list">
  <div role="listitem">列表项 1</div>
  <div role="listitem">列表项 2</div>
  <div role="listitem">列表项 3</div>
</section>
```

描述
--

任何由外部容器和内部元素列表组成的内容都可以分别使用 `list` 和 `listitem` 容器识别为辅助技术。

关于应该使用哪些元素来标记列表和列表项没有硬性规定，但是你应该确保列表项在列表的上下文中有意义，例如购物清单、食谱步骤、行车路线。

**备注：** 如果可能，你应该使用适当的语义化 HTML 元素来标记列表及列表项，如 `<ul>`、`<ol>` 和 `<li>`。有关完整示例，请参阅最佳实践。

### 关联的 WAI-ARIA 角色、状态和属性

list

项目列表。角色为 `list` 的元素必须有一个或多个角色为 `listitem` 的元素作为子元素，一个或多个角色为 `group` 的元素具有一个或多个具有 `listitem` 角色的元素作为子元素。

group (en-US)

相关对象的集合，在嵌套在列表中时仅限于列表项，其重要性不足以在页面目录中拥有自己的位置。

最佳实践
----

仅在必要时使用 `role="list"` 和 `role="listitem"`。例如，无法控制 HTML 但能够在之后动态使用 JavaScript 提升无障碍的时候。

与 HTML `<ol>` 和 `<ul>` 不同，ARIA `list` 角色不区分有序列表和无序列表。如果可能，你应该使用适当的语义 HTML 元素来标记列表（`<ol>` 和 `<ul>`）和列表项（`<li>`）。例如，我们上面的例子应该改写如下：

```html
<ul>
  <li>列表项 1</li>
  <li>列表项 2</li>
  <li>列表项 3</li>
</ul>
```

或者如果列表项的顺序很重要，则使用有序列表：

```html
<ol>
  <li>列表项 1</li>
  <li>列表项 2</li>
  <li>列表项 3</li>
</ol>
```

**备注：** ARIA `list` / `listitem` 角色不区分有序列表和无序列表。

**备注：** 给列表添加 CSS 样式 `list-style: none;` 移除列表语义。添加 `role="listitem"` 获得列表语义。

**备注：** 如果要标记将用作选项卡式界面的项目列表，则应改为使用 `tab`、`tabpanel` 和 `tablist` 角色。

规范
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # listitem |

参见
--

* HTML `<li>` 元素
* HTML `<ul>` 元素
* HTML `<ol>` 元素
* ARIA：`list` 角色
* ARIA：`group` 角色 (en-US)
* 无障碍对象模型
* HTML 中的 ARIA
* ARIA 列表示例 — by Scott O'Hara


ARIA：list 角色 - 无障碍

ARIA：list 角色
============

ARIA `list` 角色可用于标识项目列表。它通常与 `listitem` 角色结合使用，该角色用于标识包含在列表中的列表项。

```html
<section role="list">
  <div role="listitem">列表项 1</div>
  <div role="listitem">列表项 2</div>
  <div role="listitem">列表项 3</div>
</section>
```

描述
--

任何由外部容器和内部元素列表组成的内容都可以分别使用 `list` 和 `listitem` 容器识别为辅助技术。一个 `list` 必须有一个或多个 `listitem` 子级，或者，有一个或多个 `group` 作为子级，每个 `group`有一个或多个 `listitem` 作为子项。

关于应该使用哪些元素来标记 `list` 和 `listitem` 没有硬性规定，但是你应该确保 `listitem` 在列表的上下文中有意义，例如购物清单、食谱步骤、行车路线。

**警告：** 如果可能，你应该使用适当的语义化 HTML 元素来标记 `list` 及其 `listitem`，如 `<ul>`、`<ol>` 和 `<li>`。有关完整示例，请参阅 最佳实践。

### 关联的 WAI-ARIA 角色、状态和属性

listitem

列表或目录中的单个项目。角色为 listitem 的元素只能在角色为 `list` 或 `group` 的元素中找到。

group (en-US)

相关对象的集合，在嵌套在列表中时仅限于列表项，其重要性不足以在页面目录中拥有自己的位置。

最佳实践
----

仅在必要时使用 `role="list"` 和 `role="listitem"`。例如，无法控制 HTML 但能够在之后动态使用 JavaScript 提升无障碍的时候。

与 HTML `<ol>` 和 `<ul>` 不同，ARIA `list` 角色不区分有序列表和无序列表。如果可能，你应该使用适当的语义 HTML 元素来标记列表（`<ol>` 和 `<ul>`）和列表项（`<li>`）。例如，我们上面的例子应该改写如下：

```html
<ul>
  <li>列表项 1</li>
  <li>列表项 2</li>
  <li>列表项 3</li>
</ul>
```

或者如果列表项的顺序很重要，则使用有序列表：

```html
<ol>
  <li>列表项 1</li>
  <li>列表项 2</li>
  <li>列表项 3</li>
</ol>
```

**备注：** ARIA `list` / `listitem` 角色不区分有序列表和无序列表。

顺便说一句，请注意，如果你使用 `<ol>` 或 `<ul>` 的语义 HTML 元素并应用 `presentation` (en-US) 角色，则每个子 `li` 元素都会继承 `presentation` 角色，因为 ARIA 需要 `listitem` 元素具有父 `list` 元素。因此，`li` 元素不会暴露给辅助技术，但是包含在这些 `li` 元素中的元素，包括嵌套列表，对辅助技术是可见的。

**备注：** 如果要标记将用作选项卡式界面的项目列表，则应改为使用 `tab`、`tabpanel` 和 `tablist` 角色。

规范
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # list |

参见
--

* `<ul>` 元素
* `<ol>` 元素
* `<li>` 元素
* ARIA：listitem 角色
* ARIA：group 角色 (en-US)
* ARIA 列表示例——由 Scott O'Hara 撰写
* Accessibility Object Model
* ARIA in HTML


ARIA：listbox 角色 - 无障碍

ARIA：listbox 角色
===============

`listbox` 角色用于列表，用户可以从中选择一个或多个静态选项，并且与 HTML `<select>` 元素不同，它可能包含图像。

描述
--

`listbox` 角色用于标识创建列表的元素，用户可以从中选择一个或多个静态选项，类似于 HTML `<select>` 元素。与 `<select>` 不同，`listbox` 可以包含图像。`listbox` 的每个子项都应该有一个 `option` role。

强烈建议使用 HTML `<select>` 元素，如果只能选择一个选项，则使用一组单选按钮，如果可以选择多个选项，则使用一组复选框，因为有很多键盘交互来管理所有后代的焦点和原生 HTML 元素为你提供相关的功能。

具有 `listbox` 角色的元素含有隐式的 `aria-orientation` 和 `vertical` 值。

当一个列表被 tab 聚焦到时，如果没有其他内容，将会选择列表中的第一项。可以用 Up/Down 方向键在列表中导航，按 Shift + Up/Down 方向键将移动并扩展选择。键入一个或多个字母将在列表项中导航（相同的字母指向以那个开头的每个选项，不同的字母指向以整个字符串开头的第一个选项）。如果当前选项有关联的菜单，Shift+F10 将启动该菜单。如果项目可被勾选，Space 可用于切换 `checkbox` role。对于可选择的列表项，Space 切换它们的选择，Shift+Space 可用于选择连续的项目，Ctrl+ 方向键 移动而不选择，Ctrl+Space 可用于选择非连续的项目。建议使用 checkbox、link 或其他方法来选择所有项目，为此可以使用 Ctrl+A 作为快捷键。

当 listbox 角色被添加到元素中，或含有它的元素变得可见时，屏幕阅读器会在 listbox 获得焦点时读出它的 label 和 role。如果列表中的 option 或选项获得焦点，则接下来会读出它，如果屏幕阅读器支持，则会在列表中指示选项的位置。当焦点在列表中移动时，屏幕阅读器会读出相关选项。

### 相关的 ARIA 角色、状态和属性

#### 相关角色

option (en-US)

需要一个或多个嵌套的 `option`。所有被选择的选项都含有 `aria-selected` 且值为 `true`。所有未选中的选项都含有 `aria-selected` 且值为 `false`。如果某个选项不可选择，`aria-selected` 会被忽略。

list

包含 `listitem` 元素的部分

#### 状态和属性

aria-activedescendant

保存 listbox 中当前活动元素的 `id` 字符串。如果这是一个 option 元素，那么这将是最近与之交互选项的 `id`，无论该选项是否具有值为 `true` 的 `aria-selected`。即使在多选列表框中，也只会有一个 `id`。如果 `id` 不引用 listbox 的 DOM 后代，则 `id` 必须包含在 `aria-owns` 属性中的 ID 中。

aria-owns

这是一个以空格分隔的元素 ID 列表，它们不是 listbox 的 DOM 子元素。此处列出的 ID 也不能列在任何其他元素的 `aria-owns` 属性中。

aria-multiselectable

如果用户可以选择多个选项，则存在并设置为 `true`。如果设置为 `true`，*每个* 可选的选项都应包含 `aria-selected` 属性并设置为 `true` 或 `false`。 *不可选*的选项*不应该*具有`aria-selected`属性。如果值为 `false` 或被省略，那么仅当前选中的选项（如果有任何选项被选中）才需要`aria-selected`属性，而且必须设置为`true`。

aria-required

一个布尔属性，指示必须选择具有非空字符串值的选项。

aria-readonly

用户无法更改选择或取消选择，但 listbox 是可操作的。

aria-label

一个可供人类阅读的字符串，用于标识 listbox。如果有可见标签，则应使用 `aria-labelledby` 来引用该标签。

aria-labelledby

标识以空格分隔的元素 ID 列表中的一个或多个可见元素，这些元素标识 listbox。如果没有可见标签，则应该使用 `aria-label` 来包含标签。（注意：带有两个 L 的 "labelled" 是基于辅助功能 API 约定的正确拼写。）

aria-roledescription

一个可供人类阅读的字符串，可以更清楚地标识 listbox 的作用。屏幕阅读器通常会在阅读标签（如果存在）后向用户阅读此值，而不是说“listbox”。

（有关更多详细信息以及 ARIA 状态和属性的完整列表，请参阅 ARIA `listbox` (role) 文档。 )

### 键盘交互

* 当单选 listbox 获得焦点时：
    + 如果在 listbox 获得焦点之前没有选择任何选项，则第一个选项将获得焦点。（可选）可以自动选择第一个选项。
    + 如果在列表框获得焦点之前选择了一个选项，则焦点将设置在所选选项上。
* 当多选 listbox 获得焦点时：
    + 如果在列表框获得焦点之前没有选择任何选项，则焦点将设置在第一个选项上，并且选择状态不会自动更改。
    + 如果在列表框获得焦点之前选择了一个或多个选项，则焦点将设置在列表中选定的第一个选项上。
* `Down Arrow`
 : 将焦点移至下一个选项。（可选）在单选 listbox 中，选中的值也可以随焦点移动。
* `Up Arrow`
 : 将焦点移至上一个选项。（可选）在单选 listbox 中，选中的值也可以随焦点移动。
* `Home`
 (可选): 将焦点移至第一个选项。（可选）在单选列表框中，选中的值也可以随焦点移动。对于超过五个选项的列表，强烈建议支持此键。
* `End`
 (可选): 将焦点移至最后一个选项。（可选）在单选列表框中，选中的值也可以随焦点移动。对于超过五个选项的列表，强烈建议支持此键。
* 建议所有 listbox 都预先输入，尤其是那些有七个以上选项的列表框：
    + 键入字符时：焦点移至名称符合键入的字符开头的一项。
    + 快速连续键入多个字符时：焦点移至名称符合键入的字符串开头的一项。
* **多项选择**: 作者可以实现两种交互模型中的任何一种来支持多选：推荐模型，不需要用户在导航列表时按住修饰键，例如
 `Shift`
 或
 `Control`
 或者需要在导航时按住修饰键以避免丢失选择状态的替代模型。
    + 推荐的选择模型——不需要按住修饰键：
        - `Space`
         : 更改焦点选项的选择状态。
        - `Shift + Down Arrow`
         （可选）: 将焦点移动并切换到下一个选项的选定状态。
        - `Shift + Up Arrow`
         （可选）: 将焦点移动并切换到上一个选项的选定状态。
        - `Shift + Space`
         （可选）: 选择从最近选择的项目到焦点项目的连续项目。
        - `Control + Shift + Home`
         （可选）: 选择焦点选项和直到第一个选项的所有选项。（可选）将焦点移至第一个选项。
        - `Control + Shift + End`
         （可选）: 选择焦点选项和直到最后一个选项的所有选项。（可选）将焦点移到最后一个选项。
        - `Control + A`
         （可选）: 选择列表中的所有选项。（可选）如果选择了所有选项，它也可以取消选择所有选项。
### 所需的 JavaScript 功能

#### 在单选 listbox 中选择一个选项

当用户选择一个选项时，必须发生以下情况：

1. 取消选择先前选择的选项，将 aria-selected 设置为 false，或完全删除该属性，将新未选择的选项的外观更改为未选择的。
2. 选择新选择的选项，在该选项上设置 aria-selected="true" 并将新选择的选项的外观更改为选中。
3. 将列表框上的 `aria-activedescendant` 值更新为新选择的选项的 id
4. 可视化处理选项的丢焦、聚焦和选定状态

#### 在多选列表框中切换选项的状态

当用户点击一个选项、聚焦在一个选项时按下 `Space`或者以其他方式切换一个选项的状态，必须发生以下情况：

1. 切换当前聚焦选项的 aria-selected 状态，如果它是 false，则将 aria-selected 的状态更改为 true，如果为 true，则将其更改为 false。
2. 更改选项的外观以反映其选定状态
3. 将列表框上的 aria-activedescendant 值更新为用户刚刚与之交互的选项的 id，即使他们将选项切换为取消选择。

**备注：** ARIA 使用的第一原则是你可以使用具有内置语义和行为的原生功能，而不是重新利用元素并**添加** ARIA 角色、状态或属性使其可访问。含有后代 `<option>` 元素的 `<select>` 元素带有所有需要的交互的原生处理方法。

例子
--

#### 例子 1: 使用 aria-activedescendant 的单个选择列表框

下面的代码片段显示了如何将列表框角色直接添加到 html 源代码中。

```html
<p id="listbox1label" role="label">Select a color:</p>
<div
 role="listbox"
 tabindex="0"
 id="listbox1"
 aria-labelledby="listbox1label"
 onclick="return listItemClick(event);"
 onkeydown="return listItemKeyEvent(event);"
 onkeypress="return listItemKeyEvent(event);"
 aria-activedescendant="listbox1-1">
  <div role="option" id="listbox1-1" class="selected" aria-selected="true">
    Green
  </div>
  <div role="option" id="listbox1-2">Orange</div>
  <div role="option" id="listbox1-3">Red</div>
  <div role="option" id="listbox1-4">Blue</div>
  <div role="option" id="listbox1-5">Violet</div>
  <div role="option" id="listbox1-6">Periwinkle</div>
</div>
```

使用原生的 HTML `<select>` 和 `<label>` 元素可以更简单。

```html
<label for="listbox1">Select a color:</label>
<select id="listbox1">
  <option selected>Green</option>
  <option>Orange</option>
  <option>Red</option>
  <option>Blue</option>
  <option>Violet</option>
  <option>Periwinkle</option>
</select>
```

#### 更多例子

* 可滚动的 listbox 示例: 滚动显示更多选项的单选 listbox，类似于 HTML `select` 的 `size` 属性大于 1。
* 可折叠下拉 listbox 示例: 激活时展开的单选可折叠 listbox，类似于 HTML `select` 并且属性 `size="1"`。
* 具有可重新排列选项的 listbox 示例: 带有可以添加、移动和删除选项的附带工具栏的单选和多选 listbox 的示例。
最佳实践
----

* 为了便于键盘访问，作者应该对这个角色的所有后代进行 焦点管理
* 建议作者在列表未聚焦时使用不同的样式进行选择，例如非活动选项通常以较浅的背景颜色显示。
* 如果 listbox 不是另一个组件的一部分，那么它应该具有 `aria-labelledby` 属性。
* 如果一个或多个条目不是 listbox 的 DOM 子项，则需要设置额外的 `aria-*` 属性（参见 ARIA Best Practices)。
* 如果有理由 展开 列表框，`combobox` (en-US) 角色可能更合适。
规范
--

| Specification |
| --- |
| Accessible Rich Internet Applications (WAI-ARIA) # listbox |
| Unknown specification  |

参见
--

* `<select>` 元素
* `<label>` 元素
* `<option>` 元素
* ARIA: `combobox` 角色 (en-US)
* ARIA: `option` 角色 (en-US)
* ARIA: `list` 角色
* ARIA: `listitem` 角色
* ARIA Best Practices – Listbox
* ARIA Role Model – Listbox


JavaScript 中的相等性判断 - JavaScript

JavaScript 中的相等性判断
==================

JavaScript 提供三种不同的值比较运算：

* `===`——严格相等（三个等号）
* `==`——宽松相等（两个等号）
* `Object.is()`

选择哪个运算取决于你需要什么样的比较。简单来说：

* 在比较两个操作数时，双等号（`==`）将执行类型转换，并且会按照 IEEE 754 标准对 `NaN`、`-0` 和 `+0` 进行特殊处理（故 `NaN != NaN`，且 `-0 == +0`）；
* 三等号（`===`）做的比较与双等号相同（包括对 `NaN`、`-0` 和 `+0` 的特殊处理）但不进行类型转换；如果类型不同，则返回 `false`；
* `Object.is()` 既不进行类型转换，也不对 `NaN`、`-0` 和 `+0` 进行特殊处理（这使它和 `===` 在除了那些特殊数字值之外的情况具有相同的表现）。

上述三个操作分别与 JavaScript 四个相等算法中的三个相对应：

* IsLooselyEqual：`==`
* IsStrictlyEqual：`===`
* SameValue：`Object.is()`
* SameValueZero：被许多内置运算使用

请注意，这些算法的区别都与它们对原始类型值的处理有关；它们都不会比较参数是否具有理论上相似的结构。对于任何具有相同的结构，但不是同一对象本身的非原始类型对象 `x` 和 `y` ，上述所有形式都将计算为 `false`。

使用 === 进行严格相等比较
---------------

严格相等比较两个值是否相等。两个被比较的值在比较前都不进行隐式转换。如果两个被比较的值具有不同的类型，这两个值是不相等的。否则，如果两个被比较的值类型相同，值也相同，并且都不是 number 类型时，两个值相等。最后，如果两个值都是 number 类型，当两个都不是 `NaN`，并且数值相同，或是两个值分别为 `+0` 和 `-0` 时，两个值被认为是相等的。

```js
const num = 0;
const obj = new String("0");
const str = "0";

console.log(num === num); // true
console.log(obj === obj); // true
console.log(str === str); // true

console.log(num === obj); // false
console.log(num === str); // false
console.log(obj === str); // false
console.log(null === undefined); // false
console.log(obj === null); // false
console.log(obj === undefined); // false
```

在日常中使用严格相等几乎总是正确的选择。对于除了数值之外的值，严格相等使用明确的语义进行比较：一个值只与自身严格相等。对于数值，严格相等使用略加修改的语义来处理两个特殊情况：第一个情况是，浮点数 0 是不分正负的。区分 `+0` 和 `-0` 在解决一些特定的数学问题时是必要的，但是大部分情况下我们并不用关心。严格相等认为这两个值是全等的。第二个情况是，浮点数包含了 `NaN` 值，用来表示某些定义不明确的数学问题的解，例如：正无穷加负无穷。严格相等认为 `NaN` 与其他任何值都不全等，包括它自己。（等式 `(x !== x)` 成立的唯一情况是 `x` 的值为 `NaN`）

除了 `===` 之外，数组索引查找方法也使用严格相等，包括 `Array.prototype.indexOf()`、`Array.prototype.lastIndexOf()`、`TypedArray.prototype.index()`、`TypedArray.prototype.lastIndexOf()` 和 `case` 匹配。这意味着你不能使用 `indexOf(NaN)` 查找数组中 `NaN` 值的索引，也不能将 `NaN` 用作 `case` 值在 `switch` 语句中匹配任何内容。

```js
console.log([NaN].indexOf(NaN)); // -1
switch (NaN) {
  case NaN:
    console.log("Surprise"); // 没有任何输出
}
```

使用 == 进行宽松相等比较
--------------

宽松相等是*对称的*：对于任何 `A` 和 `B` 的值，`A == B` 总是与 `B == A` 具有相同的语义（除了转换应用的顺序）。使用 `==` 执行宽松相等的行为如下：

1. 如果操作数具有相同的类型，则按以下方式进行比较：
    * Object：仅当两个操作数引用相同的对象时，才返回 `true`。
    * String：仅当两个操作数具有相同的字符并且顺序相同，才返回 `true`。
    * Number：仅当两个操作数具有相同的值时，才返回 `true`。`+0` 和 `-0` 被视为相同的值。如果任一操作数为 `NaN`，则返回 `false`；因此 `NaN` 永远不等于 `NaN`。
    * Boolean：仅当操作数都是 `true` 或 `false` 时，才返回 `true`。
    * BigInt：仅当两个操作数具有相同的值时，才返回 `true`。
    * Symbol：仅当两个操作数引用相同的 symbol 时，才返回 `true`。
2. 如果操作数之一为 `null` 或 `undefined`，则另一个操作数必须为 `null` 或 `undefined` 才返回 `true`。否则返回 `false`。
3. 如果操作数之一是对象，而另一个是原始值，则将对象转换为原始值。
4. 在这一步骤中，两个操作数都被转换为原始值（String、Number、Boolean、Symbol 和 BigInt 之一）。剩余的转换将分情况完成。
    * 如果它们是相同类型的，则使用步骤 1 进行比较。
    * 如果操作数中有一个是 Symbol，但另一个不是，则返回 `false`。
    * 如果操作数之一是 Boolean，而另一个不是，则将 Boolean 转换为 Number：`true` 转换为 1，`false` 转换为 0。然后再次对两个操作数进行宽松比较。
    * Number 转 String：将 String 转换为 Number。转换失败会得到 `NaN`，这将确保相等性为 `false`。
    * Number 转 BigInt：按照其数值进行比较。如果 Number 是 `±Infinity` 或 `NaN`，返回 `false`。
    * String 转 BigInt: 使用与 `BigInt()` 构造函数相同的算法将字符串转换为 BigInt。如果转换失败，则返回 `false`。

一般而言，根据 ECMAScript 规范，所有原始类型和对象都不与 `undefined` 和 `null` 宽松相等。但是大部分浏览器允许非常有限的一类对象（即，所有页面中的 `document.all` 对象）在某些情况下表现出*模拟* `undefined` 值特性。宽松相等就是这些情况之一：当且仅当 A 是一个*模拟* `undefined` 的对象时，`null == A` 和 `undefined == A` 将会计算得到 `true`。在其他所有情况下，一个对象都不会与 `undefined` 或 `null` 宽松相等。

在大多数情况下，不建议使用宽松相等。使用严格相等进行比较的结果更容易预测，并且由于缺少类型强制转换可以更快地执行。

下面的例子演示了宽松比较，其中涉及 number 原始值 `0`、bigint 原始值 `0n`、string 原始值 `'0'` 和一个 `toString()` 值为 `'0'` 的对象。

```js
const num = 0;
const big = 0n;
const str = "0";
const obj = new String("0");

console.log(num == str); // true
console.log(big == num); // true
console.log(str == big); // true

console.log(num == obj); // true
console.log(big == obj); // true
console.log(str == obj); // true
```

宽松相等仅由 `==` 运算符使用。

使用 Object.is() 进行同值相等比较
-----------------------

同值相等决定了两个值在所有上下文中是否在功能上相同。（这个用例演示了里氏替换原则的一种情况。）这一情况会在尝试修改一个不可变属性时发生。

```js
// 向 Nmuber 构造函数添加一个不可变的属性 NEGATIVE\_ZERO
Object.defineProperty(Number, "NEGATIVE\_ZERO", {
  value: -0,
  writable: false,
  configurable: false,
  enumerable: false,
});

function attemptMutation(v) {
  Object.defineProperty(Number, "NEGATIVE\_ZERO", { value: v });
}
```

当尝试更改不可变属性时，`Object.defineProperty` 会抛出异常，但如果没有请求实际更改，则不会执行任何操作。如果 `v` 是 `-0`，则没有请求更改，也不会抛出错误。在内部，重新定义不可变属性时，使用同值相等将新指定的值与当前值进行比较。

同值相等由 `Object.is` 方法提供。语言内部期望一个值等于另一个时，几乎所有地方都使用同值相等。

零值相等
----

类似于同值相等，但 +0 和 -0 被视为相等。

零值相等不作为 JavaScript API 公开，但可以通过自定义代码实现：

```js
function sameValueZero(x, y) {
  if (typeof x === "number" && typeof y === "number") {
    // x 和 y 相等（可能是 -0 和 0）或它们都是 NaN
    return x === y || (x !== x && y !== y);
  }
  return x === y;
}
```

零值相等与严格相等的区别在于其将 `NaN` 视作是相等的，与同值相等的区别在于其将 `-0` 和 `0` 视作相等的。这使得它在搜索期间通常具有最实用的行为，特别是在与 `NaN` 一起使用时。它被用于 `Array.prototype.includes()`、`TypedArray.prototype.includes()` 及 `Map` 和 `Set` 方法用来比较键的相等性。

相等性方法比较
-------

在比较双等号和三等号时，人们通常说一个是另一个的“增强”版本。例如，双等号可以被称为三等号的扩展版本，因为前者可以执行后者的所有操作，但是会对其操作数进行类型转换——例如 `6 == "6"`。或者，也可以说双等号是基础，而三等号是增强版本，因为它要求两个操作数是相同的类型，因此增加了额外的约束。

然而，这种思维方式意味着相等比较形成了一个一维的“光谱”，其中“完全严格”位于一端，“完全宽松”位于另一端。这个模型在 `Object.is` 方面存在缺陷，因为它既不比双等号“宽松”，也不比三等号“严格”，也不处于两者之间（可以说既比双等号严格，又比三等号宽松）。从下面的相同比较表中，我们可以看出这是由于 `Object.is` 处理 `NaN` 的方式。请注意，如果 `Object.is(NaN, NaN)` 求值得到 `false`，我们*可以*说它适合宽松/严格光谱，作为三等号的更严格形式，可以区分 `-0` 和 `+0` 。然而，`NaN` 的处理意味着这是不正确的。不幸的是，`Object.is` 必须根据其特定特征来考虑，而不是根据其相等运算符的宽松度或严格度来考虑。

| x | y | `==` | `===` | `Object.is` | `SameValueZero` |
| --- | --- | --- | --- | --- | --- |
| `undefined` | `undefined` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `null` | `null` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `true` | `true` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `false` | `false` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `'foo'` | `'foo'` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `0` | `0` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `+0` | `-0` | `✅ true` | `✅ true` | `❌ false` | `✅ true` |
| `+0` | `0` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `-0` | `0` | `✅ true` | `✅ true` | `❌ false` | `✅ true` |
| `0n` | `-0n` | `✅ true` | `✅ true` | `✅ true` | `✅ true` |
| `0` | `false` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `""` | `false` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `""` | `0` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `'0'` | `0` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `'17'` | `17` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `[1, 2]` | `'1,2'` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `new String('foo')` | `'foo'` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `null` | `undefined` | `✅ true` | `❌ false` | `❌ false` | `❌ false` |
| `null` | `false` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `undefined` | `false` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `{ foo: 'bar' }` | `{ foo: 'bar' }` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `new String('foo')` | `new String('foo')` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `0` | `null` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `0` | `NaN` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `'foo'` | `NaN` | `❌ false` | `❌ false` | `❌ false` | `❌ false` |
| `NaN` | `NaN` | `❌ false` | `❌ false` | `✅ true` | `✅ true` |

### 何时使用 Object.is() 而不是三等号

通常情况下，唯一需要关注 `Object.is` 对零的特殊行为的时机是在实施特定的元编程范式时，特别是涉及属性描述符时，当你的工作需要镜像 `Object.defineProperty` 的某些特性时。如果你的用例不需要这样做，建议避免使用 `Object.is`，而改用 `===`。即使你的要求涉及将两个 `NaN` 值之间的比较计算为 `true`，通常特殊处理 `NaN` 检查（使用先前版本的 ECMAScript 中提供的 `isNaN` 方法）比解决相关计算如何影响零的符号更为简单。

这是一个不全面的列表，其中包含可能导致你的代码中出现 `-0` 和 `+0` 之间差异的内置方法和运算符：

`-`（一元减）

考虑以下例子：

```js
const stoppingForce = obj.mass \* -obj.velocity;
```

如果 `obj.velocity` 是 `0`（或计算为 `0`），则在该位置引入 `-0` 并向 `stoppingForce` 传播。

`Math.atan2`、`Math.ceil`、`Math.pow`、`Math.round`

在某些情况下，即使没有 `-0` 作为参数之一，这些方法的返回值仍可能作为表达式中的 `-0` 被引入。例如，使用 `Math.pow` 将 `-Infinity` 的任何负奇数次幂求值为 `-0`。请参阅各个方法的文档。

`Math.floor`、`Math.max`、`Math.min`、`Math.sin`、`Math.sqrt`、`Math.tan`

在某些情况下，当参数中存在 `-0` 时，这些方法可能会返回一个 `-0` 值。例如，`Math.min(-0, +0)` 的计算结果为 `-0`。请参考各个方法的文档。

`~`、`<<`、`>>`

这些运算符中的每一个都在内部使用 ToInt32 算法。由于在内部 32 位整数类型中只有一个表示 0 的表示形式，`-0` 在反向操作后将不会存在。例如，`Object.is(~~(-0), -0)` 和 `Object.is(-0 << 2 >> 2, -0)` 都会计算为 `false`。

如果不考虑零的符号，依赖于 `Object.is` 可能会很危险。当意图区分 `-0` 和 `+0` 时，它当然会做到期望的效果。

### 注意：Object.is() 和 NaN

`Object.is` 规范将所有 `NaN` 的实例视为同一对象。然而，由于可以使用类型化数组，我们可以拥有 `NaN` 的不同浮点表示，这些表示在所有上下文中的行为不完全相同。例如：

```js
const f2b = (x) => new Uint8Array(new Float64Array([x]).buffer);
const b2f = (x) => new Float64Array(x.buffer)[0];
// 得到 NaN 的字节表示
const n = f2b(NaN);
// 改变第一位，该位表示符号且与 NaN 无关
n[0] = 1;
const nan2 = b2f(n);
console.log(nan2); // NaN
console.log(Object.is(nan2, NaN)); // true
console.log(f2b(NaN)); // Uint8Array(8) [0, 0, 0, 0, 0, 0, 248, 127]
console.log(f2b(nan2)); // Uint8Array(8) [1, 0, 0, 0, 0, 0, 248, 127]
```

参见
--

* JS 比较表


属性的可枚举性和所有权 - JavaScript

属性的可枚举性和所有权
===========

可枚举属性是指那些内部“可枚举”标志设置为 `true` 的属性，对于通过直接的赋值和属性初始化的属性，该标识值默认为即为 `true`，对于通过 Object.defineProperty 等定义的属性，该标识值默认为 `false`。可枚举的属性可以通过 for...in 循环进行遍历（除非该属性名是一个 Symbol）。属性的所有权是通过判断该属性是否直接属于某个对象决定的，而不是通过原型链继承的。一个对象的所有的属性可以一次性的获取到。有一些内置的方法可以用于判断、迭代/枚举以及获取对象的一个或一组属性，下表对这些方法进行了列举。对于部分不可用的类别，下方的示例代码对获取方法进行了演示。

属性的可枚举性和所有权 - 内置的判断、访问和迭代方法| 作用 | 自身对象 | 自身对象及其原型链 | 仅原型链 |
| --- | --- | --- | --- |
| 判断 |

| 可枚举属性 | 不可枚举属性 | 可枚举属性及不可枚举属性 |
| --- | --- | --- |
| `propertyIsEnumerable``hasOwnProperty` | `hasOwnProperty`
 获取属性后使用
 `propertyIsEnumerable`
 过滤可枚举属性
  | `hasOwnProperty` |

 |

| 可枚举属性 | 不可枚举属性 | 可枚举属性及不可枚举属性 |
| --- | --- | --- |
| 需要额外代码实现 | 需要额外代码实现 | `in` |

 | 需要额外代码实现 |
| 访问 |

| 可枚举属性 | 不可枚举属性 | 可枚举属性及不可枚举属性 |
| --- | --- | --- |
| `Object.keys``getOwnPropertyNames``getOwnPropertySymbols` | `getOwnPropertyNames`、`getOwnPropertySymbols` 获取属性后使用
 `propertyIsEnumerable`
 过滤可枚举属性
  | `getOwnPropertyNames``getOwnPropertySymbols` |

 | 需要额外代码实现 | 需要额外代码实现 |
| 迭代 |

| 可枚举属性 | 不可枚举属性 | 可枚举属性及不可枚举属性 |
| --- | --- | --- |
| `Object.keys``getOwnPropertyNames``getOwnPropertySymbols` | `getOwnPropertyNames`、`getOwnPropertySymbols`
 获取属性后使用
 `propertyIsEnumerable`
 过滤可枚举属性
  | `getOwnPropertyNames``getOwnPropertySymbols` |

 |

| 可枚举属性 | 不可枚举属性 | 可枚举属性及不可枚举属性 |
| --- | --- | --- |
| `for..in`（同时会排除 Symbol） | 需要额外代码实现 | 需要额外代码实现 |

 | 需要额外代码实现 |

通过可枚举性和所有权获取对象的属性
-----------------

注：以下实现并非使用于所有情况的最优算法，但可以快捷的展示语言特性。

* 使用 `SimplePropertyRetriever.theGetMethodYouWant(obj).indexOf(prop) > -1` 时将发生判断操作。
* 使用 `SimplePropertyRetriever.theGetMethodYouWant(obj).forEach(function (value, prop) {});` 时将发生迭代操作。 (或使用 `filter()`、`map()` 等方法)

```js
var SimplePropertyRetriever = {
  getOwnEnumerables: function (obj) {
    return this.\_getPropertyNames(obj, true, false, this._enumerable);
    // Or could use for..in filtered with hasOwnProperty or just this: return Object.keys(obj);
  },
  getOwnNonenumerables: function (obj) {
    return this.\_getPropertyNames(obj, true, false, this._notEnumerable);
  },
  getOwnEnumerablesAndNonenumerables: function (obj) {
    return this.\_getPropertyNames(
      obj,
      true,
      false,
      this._enumerableAndNotEnumerable,
    );
    // Or just use: return Object.getOwnPropertyNames(obj);
  },
  getPrototypeEnumerables: function (obj) {
    return this.\_getPropertyNames(obj, false, true, this._enumerable);
  },
  getPrototypeNonenumerables: function (obj) {
    return this.\_getPropertyNames(obj, false, true, this._notEnumerable);
  },
  getPrototypeEnumerablesAndNonenumerables: function (obj) {
    return this.\_getPropertyNames(
      obj,
      false,
      true,
      this._enumerableAndNotEnumerable,
    );
  },
  getOwnAndPrototypeEnumerables: function (obj) {
    return this.\_getPropertyNames(obj, true, true, this._enumerable);
    // Or could use unfiltered for..in
  },
  getOwnAndPrototypeNonenumerables: function (obj) {
    return this.\_getPropertyNames(obj, true, true, this._notEnumerable);
  },
  getOwnAndPrototypeEnumerablesAndNonenumerables: function (obj) {
    return this.\_getPropertyNames(
      obj,
      true,
      true,
      this._enumerableAndNotEnumerable,
    );
  },
  // Private static property checker callbacks
  \_enumerable: function (obj, prop) {
    return obj.propertyIsEnumerable(prop);
  },
  \_notEnumerable: function (obj, prop) {
    return !obj.propertyIsEnumerable(prop);
  },
  \_enumerableAndNotEnumerable: function (obj, prop) {
    return true;
  },
  // Inspired by http://stackoverflow.com/a/8024294/271577
  \_getPropertyNames: function getAllPropertyNames(
    obj,
 iterateSelfBool,
 iteratePrototypeBool,
 includePropCb,
  ) {
    var props = [];

    do {
      if (iterateSelfBool) {
        Object.getOwnPropertyNames(obj).forEach(function (prop) {
          if (props.indexOf(prop) === -1 && includePropCb(obj, prop)) {
            props.push(prop);
          }
        });
      }
      if (!iteratePrototypeBool) {
        break;
      }
      iterateSelfBool = true;
    } while ((obj = Object.getPrototypeOf(obj)));

    return props;
  },
};
```

统计表
---

|  | `in` | `for..in` | `obj.hasOwnProperty` | `obj.propertyIsEnumerable` | `Object.keys` | `Object.getOwnPropertyNames` | `Object.getOwnPropertyDescriptors` | `Reflect.ownKeys()` |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 自身的可枚举属性 | true | true | true | true | true | true | true | true |
| 自身的不可枚举属性 | true | false | true | false | false | true | true | true |
| 自身的 Symbol 键 | true | false | true | true | false | false | true | true |
| 继承的可枚举属性 | true | true | false | false | false | false | false | false |
| 继承的不可枚举属性 | true | false | false | false | false | false | false | false |
| 继承的 Symbol 键 | true | false | false | false | false | false | false | false |

参见
--

* `in`
* `for..in`
* `Object.hasOwnProperty()`
* `Object.propertyIsEnumerable()`
* `Object.getOwnPropertyNames()`
* `Object.keys()`
* `Object.getOwnPropertyDescriptors()`