ARIA 实时区域

使用 JavaScript,可以在不重新加载整个页面的情况下动态更改页面的部分内容——例如,即时更新搜索结果列表,或显示一个不需要用户交互的、不显眼的警报或通知。虽然这些更改通常对能看到页面的用户来说是显而易见的,但对于使用辅助技术的用户来说可能并不明显。ARIA 实时区域填补了这一空白,提供了一种以可被辅助技术播报的方式来以编程方式公开动态内容更改的方法。

注意:辅助技术通常只会播报实时区域内容中发生的动态更改。只要在更改发生之前添加 aria-live 属性或专门的实时区域 role(例如 role="status"),就能使您希望播报更改的元素得到播报,无论是通过原始的 HTML 标记,还是通过 JavaScript 动态添加。先有一个空的实时区域,然后——在另一个独立的步骤中——更改区域内的内容。尽管规范中没有明确说明,但浏览器/辅助技术对 role="alert" 进行了特殊的处理:在大多数情况下,即使区域(已包含通知/消息)存在于页面初始标记中,或被动态注入到页面中,role="alert" 区域内的内容也会被播报。但是,请注意,根据具体的浏览器/辅助技术组合,role="alert" 区域在播报时会自动加上“警报”的前缀。

实时区域

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

aria-livearia-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",屏幕阅读器将在用户暂停时等待,然后播报更新。因此,在列表中向下滚动并选择另一个行星不会播报实时区域的更新。实时区域的更新仅为最终选择的行星播报。

这是 VoiceOver 在 Mac 上播报实时区域更新(通过字幕)的截图

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-valuemaxaria-valuenow 一起使用。(待定:此处添加更多信息)。
marquee 滚动的文本,例如股票行情显示器。
timer 任何类型的计时器或时钟,例如倒计时器或秒表读数。

附加的实时区域属性

实时区域得到了很好的支持。The Paciello Group 在 2014 年发布了 关于实时区域支持情况的信息。Paul J. Adam 研究了 aria-atomicaria-relevant 的支持情况

  1. aria-atomicaria-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()}`.slice(-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" />
</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;
  }
}

document.getElementById("year").addEventListener("blur", change);

如果不设置 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" 确保会播报添加到名单或从名单移除的用户。

另见