Skip to content
返回设计中心

动态更新的实时区域

向屏幕阅读器播报异步状态变化(toast、搜索结果、表单错误)。

无障碍进阶

为什么

toast 出现或搜索结果更新时,视力用户即时见。屏幕阅读器用户无实时区域则听不到 — 以为啥也没发生。

WebAIM Million 2024 报告发现 96.3% 的首页存在可检测的 WCAG 失败。2023 年 ADA 相关诉讼超过 4,500 起,使无障碍成为法律和伦理必需,而非可有可无。

何时使用

任何用户需知的异步更新用实时区域:toast、即输即搜结果、表单校验错误、加载→完成转换、购物车数变。不要将无障碍视为最终阶段清单 — 事后改造成本是内置的 10 倍。

避免仅依赖自动扫描器;它们只能发现约 40% 的问题。

如何做

1. polite — aria-live="polite" 非紧急(搜索结果、购物车数);用户暂停时播报 2. assertive — aria-live="assertive" 紧急(错误、会话过期);打断当前语音 3. atomic — aria-atomic="true" 播报整区域,非仅变节点 4. relevant — aria-relevant="additions text"(默认)控制何变化播报 5. 预声明 — 初始 HTML 放空实时区域,后更新内容;动态加 aria-live 不可靠 6. 角色 — role="status" 隐含 polite+atomic;role="alert" 隐含 assertive+atomic 7. 测试 — NVDA/VoiceOver:触发更新,验证不移焦点即播报

示例

<!-- 布局中预声明空实时区域 --> <div id="toast-region" role="status" aria-live="polite" aria-atomic="true" class="sr-only"></div> <div id="alert-region" role="alert" aria-live="assertive" aria-atomic="true" class="sr-only"></div> // Toast — 写入 polite 区域 function showToast(msg: string) { document.getElementById("toast-region")!.textContent = msg; } showToast("已存收藏"); // NVDA:"已存收藏"(当前语音完后) // 搜索结果 — 播报数量 function onResults(items: Item[]) { document.getElementById("toast-region")!.textContent = `${items.length} 个结果可用`; } // 表单错误 — assertive,打断 function showError(msg: string) { document.getElementById("alert-region")!.textContent = msg; } showError("邮箱必填"); // NVDA:"邮箱必填"(打断)

常见问题

  • ⚠动态加 aria-live — 屏幕阅读器不拾取,更新静默
  • ⚠处处 assertive — 持续打断,用户听不到其他
  • ⚠移焦点而非用实时区域 — 让用户迷失,丢位置

最佳实践

  • ✓静态 HTML 预声明实时区域 — 更新内容非属性
  • ✓默认 polite — assertive 留给需即时注意的真错误
  • ✓用 role=status / role=alert — 隐含对的 live+atomic 组合,少记

常见问题解答