用代码触发屏幕阅读器播报:ariaNotify() 让前端交互终于有「声音」了

用代码触发屏幕阅读器播报:ariaNotify() 让前端交互终于有「声音」了

导语

做前端交互的时候,你有没有遇到过这种场景:表单提交成功了、搜索有结果了、文件上传完了,界面上明明有变化,但用屏幕阅读器的用户就是感知不到?以前我们只能用 aria-live 塞个隐藏节点,现在浏览器原生给了你一个更直接的办法——ariaNotify(),一行代码就能让辅助技术「开口说话」。

正文

问题:动态更新对屏幕阅读器用户是盲区

现代前端应用大量依赖即时反馈:搜索框下面实时出结果、表单提交后弹个 toast、侧边栏打开个抽屉。视觉上没问题,但对依赖屏幕阅读器的用户来说,这些变化如果没有正确的无障碍标记,等于不存在。

传统的解决方案是 ARIA live region

思路没错,但有几个真实的痛点:

  • 必须改 DOM 才能触发播报,有时候你想播报的内容和页面元素无关(比如「数据已保存」这种纯状态提示);
  • 屏幕外节点 hack 很常见,就是把 live region 放在 position: absolute; left: -9999px 的地方,但这样可能被屏幕阅读器意外读到;
  • 多段消息顺序不可控,如果短时间内触发了多条通知,读屏软件可能乱序或合并处理;
  • 优先级没有区分,一条「数据丢失警告」和一条「加载完成」在 live region 里没有任何优先级差异。

方案:ariaNotify() 原生 API

微软在 Edge 136 里通过 Origin Trial 引入了 ariaNotify(),现在已经写进了 MDN Web API 文档,W3C ARIA 社区组也在跟进标准化。

它的核心思路是:不用改 DOM,直接让浏览器把一段文本推给辅助技术

基本用法

// 在任意元素上调用(文档对象也行)
const button = document.querySelector('#submit-btn');

button.ariaNotify('表单提交成功');
button.ariaNotify('文件已保存到云端', { priority: 'high' });

参数说明:

  • announcement:要播报的纯文本;
  • options.priority'normal'(默认,等当前播报完再说)或 'high'(立即打断当前播报)。

与 ARIA live region 的对应关系

场景 live region 做法 ariaNotify() 做法
普通状态提示 更新 live region 的 textContent `element.ariaNotify(‘已保存’)`
紧急警告 `aria-live=”assertive”` `{ priority: ‘high’ }`
纯逻辑事件(无 DOM 变化) 需要创建隐藏 live region 直接调用,无需 DOM
多段消息合并 手动拼字符串 建议合并为一条,避免乱序

代码示例:实际项目里的用法

场景 1:表单提交反馈

async function handleSubmit(formData) {
  try {
    await submitToServer(formData);
    // 成功提示——用 normal 优先级,不打断用户当前操作
    document.ariaNotify('表单提交成功,感谢你的反馈');
  } catch (error) {
    // 错误提示——用 high 优先级,立即告知
    document.ariaNotify('提交失败,请检查网络连接后重试', {
      priority: 'high',
    });
  }
}

场景 2:搜索无结果

function showSearchEmpty(query) {
  // 传统的 live region 方式
  // liveRegion.textContent = `没有找到"${query}"相关结果`;

  // ariaNotify 方式
  searchInput.ariaNotify(`没有找到"${query}"相关结果,请尝试其他关键词`);
}

场景 3:多步骤向导

function announceStep(step, total) {
  // 把多条信息合并成一条,避免读屏软件乱序
  const message = `第 ${step} 步,共 ${total} 步:请填写你的联系信息`;
  document.ariaNotify(message, { priority: 'normal' });
}

兼容性现状

目前 ariaNotify() 的真实支持情况:

  • Edge 136+:Origin Trial 可用,需开启 --enable-blink-features=AriaNotify 或通过 Origin Trial token;
  • 其他 Chromium 浏览器:实现中,尚未默认开启;
  • Firefox / Safari:暂无公开实现计划;
  • GitHub 已有 polyfillgithub/ariaNotify-polyfill,通过 @live-region 自定义元素模拟行为。

也就是说,现在还不能直接全量上线,但有两个落地思路:

  • 渐进增强:检测 'ariaNotify' in document,有就用原生,没有回退到 live region;
  • 封装一层适配器:项目里统一走 a11y.announce() 方法,内部自动选最优实现。

结论与判断标准

ariaNotify() 解决的其实是一个老问题:前端怎么优雅地「喊」一声

什么时候该用它:

  • 你现在的代码里已经有用隐藏 live region 做播报的逻辑 → 换成 ariaNotify() 会更干净;
  • 你的事件触发和 DOM 变化没有直接关系 → ariaNotify() 比 live region 更自然;
  • 你需要区分通知的优先级 → priority: 'high'aria-live="assertive" 语义更清晰。

什么时候先等等:

  • 需要支持非 Chromium 浏览器的用户占比还很高 → 先用 live region 或 polyfill;
  • 你的播报逻辑已经很稳定,没有维护成本 → 不必为了用 API 而重构。

收尾

无障碍不是「等项目做完再加的功能」,它是交互设计的一部分。ariaNotify() 还没全面落地,但这个信号很明确:浏览器厂商正在把「让屏幕阅读器用户获得同等体验」这件事从「开发者自己 hack」变成「浏览器原生支持」。现在可以先把 polyfill 接上,等 Chromium 默认支持那天,你的代码已经 ready 了。

评论区

0 条评论

登录后可评论。

查看完整榜单
查看完整榜单
查看完整榜单