配了三年无障碍,每次想让屏幕阅读器「说句话」都要靠一个看不见的 div 骗它——今天这件事被 ariaNotify() 彻底原生化了
每次用户点了按钮,你都得给他一个视觉反馈:弹个 toast、换个图标、在角落里加个数字。但视觉反馈对视障用户没用——他们靠屏幕阅读器。你得专门写一段「看不见的文案」,塞进一个带 aria-live="polite" 的空 div 里,等着它被屏幕阅读器扫到:
// 传统方案:藏一个 div 等屏幕阅读器来读
const announcer = document.getElementById("sr-announcer");
announcer.textContent = "";
requestAnimationFrame(() => {
announcer.textContent = "文件已保存";
});
这套机制有四个根深蒂固的问题:时序依赖 requestAnimationFrame 不然读不到、多个异步操作同时触发会乱序、DOM 被清掉再填上容易触发重复朗读、还有些读屏软件根本不配合——它不总是在最适合的时机读。
document.ariaNotify() 把这件事做成了正经 API,直接让浏览器帮你触发读屏,不用碰 DOM。
ariaNotify() 怎么用
// 基础用法:直接在元素上调用
button.ariaNotify("文件已保存");
// 紧急提示:立即打断当前朗读,类似 aria-live="assertive"
form.ariaNotify("提交失败,请检查网络", { priority: "high" });
// 全局公告:用 document 对象
document.ariaNotify("页面已加载完成");
// 合并重复通知:同 ID 的后者覆盖前者
searchInput.ariaNotify(`${count} 条结果`, {
priority: "none",
notificationId: "search-count"
});
三个关键参数:
- priority:默认
normal(等当前朗读结束),设为high立即打断,相当于aria-live="assertive" - notificationId:去重 ID,快速连续调用同一 ID 时只保留最后一条,避免屏幕阅读器被刷屏
- interrupt:
all/pending/none,控制是否打断队列里已有的通知
四个具体场景
场景一:表单提交反馈
async function handleSubmit(formData) {
try {
await submitToServer(formData);
// 成功提示用 normal,不打断用户当前操作
document.ariaNotify("表单提交成功");
} catch (error) {
// 错误提示用 high,立即告知
document.ariaNotify("提交失败,请检查网络后重试", { priority: "high" });
}
}
场景二:搜索无结果
function showSearchEmpty(query) {
searchInput.ariaNotify(`没有找到"${query}"相关结果,请尝试其他关键词`);
}
场景三:表格行删除确认
const grid = document.querySelector("[role="grid"]");
grid.ariaNotify("第 3 行已删除", { priority: "normal" });
注意:多段信息建议合并成一条读,屏幕阅读器不保证按顺序读多条通知。
浏览器支持情况
| 浏览器 | 支持版本 |
|---|---|
| Chrome | 141+ |
| Edge | 141+ |
| Firefox | 暂未支持 |
| Safari | 暂未支持 |
| iOS Safari | 暂未支持 |
Windows NVDA + Chrome/Firefox/Edge 全部验证通过,macOS VoiceOver + Safari 暂不支持。
生产环境必须有降级方案:
function announce(msg, urgent = false) {
if ("ariaNotify" in document) {
document.ariaNotify(msg, { priority: urgent ? "high" : "normal" });
} else {
// 降级:找现有的 aria-live 元素
const announcer = document.getElementById("sr-announcer");
announcer.textContent = "";
requestAnimationFrame(() => {
announcer.textContent = msg;
});
}
}
三个坑
坑一:Safari 和 iOS 暂不支持。如果你有大量 iOS 用户,不能把它当主力方案。现阶段只能做渐进增强:优先检测 ariaNotify,没有就走原有 live region 方案。
坑二:priority high 不等于最高优先级。正在朗读的 aria-live="assertive" 会排在 ariaNotify 的 high 通知前面。这意味着混用两种机制时,high 通知实际可能还是会被延迟。
坑三:不要拿来当通用通知系统。屏幕阅读器用户不是在听你应用里的所有状态变化——他们只关心「影响下一步操作」的信息。滥用 ariaNotify 会把读屏变成噪音,反而更难用。CSS-Tricks 的评论里有人说得直接:这个 API 是「last resort」,不是「convenience API」。
下一步
- 查一下你的项目里有没有
aria-live的 announcer div——如果只有一两个,可以考虑迁移到ariaNotify - 写一个
announce()封装函数,内部做 feature detection,对外保持announce(msg, urgent)接口不变 - 最重要的一件事:找一台读屏软件跑一遍你的核心流程,确认哪些状态变化从来没被播报过——那才是这个 API 真正该补的地方
ariaNotify 让「让读屏说话」从 DOM hack 变成了正经 API,但它的本质是补足浏览器的能力缺口,不是给你的 toast 系统加个外接喇叭。用对地方,它解决的是视障用户长期被忽视的体验问题;用错地方,它会成为新的噪音源。
评论区
登录后可评论。