ARIA 实时区域

使用 JavaScript,可以动态更改页面的部分内容,而无需重新加载整个页面——例如,动态更新搜索结果列表,或显示不需要用户交互的离散警报或通知。虽然这些更改通常对可以看到页面的用户来说是视觉上明显的,但它们可能不会对使用辅助技术的用户很明显。ARIA 实时区域弥合了这一差距,并提供了一种以辅助技术可以宣布的方式以编程方式公开动态内容更改的方法。

注意: 辅助技术通常只宣布实时区域内容的动态更改。在您想要宣布更改的元素上包含 aria-live 属性或专门的实时区域 role(例如 role="status")在更改发生之前有效——无论是在原始标记中,还是使用 JavaScript 动态添加。从一个空的实时区域开始,然后——在单独的步骤中——更改区域内的内容。虽然规范中没有明确说明,但浏览器/辅助技术确实包含对 role="alert" 的特殊处理:在大多数情况下,即使区域(已经包含通知/消息)存在于页面的初始标记中,或动态注入到页面中,role="alert" 区域内的内容也会被宣布。但是,请注意,role="alert" 区域在宣布时会——根据特定的浏览器/辅助技术组合——自动添加前缀“Alert”。

实时区域

在不重新加载页面的情况下更新的动态内容通常是区域或小部件。不具有交互性的简单内容更改应标记为实时区域。实时区域使用 aria-live 属性明确表示。

aria-live: aria-live=POLITENESS_SETTING 用于设置屏幕阅读器处理实时区域更新的优先级——可能的设置包括:offpoliteassertive。此属性是迄今为止最重要的属性。

通常,只使用 aria-live="polite"。任何接收对用户来说重要的更新的区域,但更新速度不快到令人讨厌,都应该接收此属性。屏幕阅读器将在用户空闲时说出更改。

aria-live="assertive" 仅应用于绝对需要用户立即注意的时间敏感/关键通知。通常,对断言式实时区域的更改会中断屏幕阅读器当前正在进行的任何宣布。因此,它可能非常烦人且具有破坏性,并且应该谨慎使用。

与直觉相反,aria-live="off" 并不表示不应宣布更改。当元素具有 aria-live="off"(或具有此隐式值的 role,例如 role="marquee"role="timer")时,元素内容的更改仅应在焦点位于元素上或元素内时宣布。

基本示例:下拉框更新有用的屏幕信息

一个专门提供行星信息的网站提供了一个下拉框。当从下拉框中选择一个行星时,页面上的一个区域将更新为包含所选行星的信息。

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 from
    <a href="https://en.wikipedia.org/wiki/Solar_System">Wikipedia</a>
  </small>
</p>
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.

具有隐式实时区域属性的角色

具有以下 role="…" 值的元素默认情况下充当实时区域

角色 描述 兼容性说明
log 聊天、错误、游戏或其他类型的日志 为了最大限度地提高兼容性,在使用此角色时添加冗余的 aria-live="polite"
status 状态栏或屏幕区域,提供某种类型的更新状态。屏幕阅读器用户有一个特殊的命令来阅读当前状态。 为了最大限度地提高兼容性,在使用此角色时添加冗余的 aria-live="polite"
alert 在屏幕上闪烁的错误或警告消息。警报对于客户端验证通知用户特别重要。 警报示例。 为了最大限度地提高兼容性,有些人建议在使用此角色时添加冗余的 aria-live="assertive"。但是,添加 aria-liverole="alert" 会在 iOS 上的 VoiceOver 中导致双重朗读问题。
progressbar 小部件和实时区域的混合体。与 aria-valueminaria-valuenowaria-valuemax 结合使用。(待定:在此处添加更多信息)。
marquee 滚动文本,例如股票行情播报。
计时器 任何类型的计时器或时钟,例如倒计时器或秒表读数。

其他实时区域属性

动态区域得到很好的支持。Paciello Group 于 2014 年发布了 关于动态区域支持状况的信息。Paul J. Adam 特别研究了 aria-atomicaria-relevant 的支持情况

  1. aria-atomic: aria-atomic=BOOLEAN 用于设置屏幕阅读器是否应始终将动态区域作为整体呈现,即使只有该区域的一部分发生变化。可能的设置是:falsetrue。默认设置为 false
  2. aria-relevant : aria-relevant=[LIST_OF_CHANGES] 用于设置哪些类型的更改与动态区域相关。可能的设置是以下一项或多项:additionsremovalstextall。默认设置为:additions text

基本示例:aria-atomic

作为 aria-atomic 的说明,假设一个网站有一个简单的时钟,显示小时和分钟。时钟每分钟更新一次,新的剩余时间覆盖当前内容。

html
<div id="clock" role="timer" aria-live="polite">
  <span id="clock-hours"></span>
  <span id="clock-mins"></span>
</div>
js
/* basic JavaScript to update the clock */
function updateClock() {
  const now = new Date();
  document.getElementById("clock-hours").textContent = now.getHours();
  document.getElementById("clock-mins").textContent =
    `0${now.getMinutes()}`.substr(-2);
}

/* first run */
updateClock();

/* update every minute */
setInterval(updateClock, 60000);

函数首次执行时,将宣布添加的整个字符串。在随后的调用中,将仅宣布与先前内容相比发生变化的内容部分。例如,当时钟从“17:33”变为“17:34”时,辅助技术将仅宣布“34”,这对用户来说不太有用。

解决此问题的一种方法是首先清除动态区域的所有内容(在本例中,将 <span id="clock-hours"><span id="clock-mins">innerHTML 设置为空),然后注入新内容。但是,这有时可能不可靠,因为它依赖于这两个更新的确切时间。

aria-atomic="true" 确保每次更新动态区域时,都会完整宣布所有内容(例如,“17:34”)。

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

aria-atomic 的另一个示例 - 由于用户操作而进行的更新/通知。

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

<div id="date-output" aria-atomic="true" aria-live="polite">
  The set year is:
  <span id="year-output">1990</span>
</div>
js
function change(event) {
  const yearOut = document.getElementById("year-output");

  switch (event.target.id) {
    case "year":
      yearOut.textContent = event.target.value;
      break;
    default:
      return;
  }
}

如果没有 aria-atomic="true",屏幕阅读器只会宣布年份的更改值。使用 aria-atomic="true",屏幕阅读器会宣布“已设置的年份为:更改的值”。

基本示例:aria-relevant

使用 aria-relevant,您可以指定应宣布哪些类型的更改/更新到动态区域。

例如,考虑一个聊天网站,该网站希望显示当前登录用户的列表。我们不仅希望宣布当前登录的用户,还希望在用户列表中删除时触发公告。我们可以通过指定 aria-relevant="additions removals" 来实现这一点。

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

ARIA 动态属性的细分

  • aria-live="polite" 表示屏幕阅读器应等到用户处于空闲状态后才能向用户显示更新。这是最常用的值,因为用“assertive”中断用户可能会中断他们的流程。
  • aria-atomic 未设置(默认情况下为 false),因此只有添加或删除的用户才会被说出,每次不会说出整个花名册。
  • aria-relevant="additions removals" 确保添加或删除到花名册中的用户都会被说出。

另请参阅