aria-busy不是魔法属性,仅向辅助技术声明“内容正在动态更新,请暂勿播报”,不控制UI、不触发动画、不禁用交互;须配合JS手动设为"true"/"false"、CSS样式及交互逻辑。

直接说结论: aria-busy 不是“让元素变加载中”的魔法属性,它只是向辅助技术(如读屏软件)声明“这个区域内容正在动态更新,暂时别读”,本身不控制 UI 显示、不触发 CSS 动画、也不阻止用户操作 —— 你得自己用 JS 控制显隐、禁用、加 loading 图标。
什么时候该用 aria-busy?
适用场景非常明确:当某个容器(比如 <div id="list">)正通过 AJAX 替换内部 HTML,且替换过程有明显延迟(>300ms),又希望读屏用户不读到中间状态(比如只读到半截列表、或旧数据+新数据混杂)时,才需要它。
常见误用:
• 给按钮加 aria-busy="true" 代替 disabled —— 这没用,按钮照样能点,读屏也不会跳过它;
• 在整个页面 <body> 上设 aria-busy —— 范围太大,辅助技术可能直接跳过所有交互,体验更差。
正确做法是:只标注**实际在刷新的内容区块**,例如:
<div id="search-results" aria-busy="false"> <p>搜索结果将显示在这里</p> </div>
aria-busy 的取值和 JS 控制逻辑
它只有两个合法值:"true" 和 "false"(注意是字符串,不是布尔字面量)。不能写 aria-busy 或 aria-busy="pending",否则无效。
立即学习“前端免费学习笔记(深入)”;
典型控制流程:
- 发起请求前:
el.setAttribute('aria-busy', 'true'),同时可加 class 如is-loading控制样式 - 请求完成(无论成功失败):
el.setAttribute('aria-busy', 'false'),再更新 DOM 或报错提示 - 务必确保
aria-busy="false"被执行 —— Promise.finally()是最稳妥的位置,避免因异常遗漏恢复
示例片段:
const resultsEl = document.getElementById('search-results');
fetch('/api/search?q=' + q)
.then(r => r.json())
.then(data => {
resultsEl.innerHTML = renderList(data);
})
.finally(() => {
resultsEl.setAttribute('aria-busy', 'false');
});
// 发起前记得先设为 true
resultsEl.setAttribute('aria-busy', 'true');
CSS 和交互要自己补全,aria-busy 不负责
仅设 aria-busy="true" 不会让元素变灰、加 loading 圆圈、或禁用点击。这些必须手动处理:
- 视觉反馈:用 CSS 选中
[aria-busy="true"]加 loading 背景或伪元素,例如[aria-busy="true"]::after { content: "⏳"; } - 防重复提交:对触发刷新的按钮,需同步设
disabled或用节流(debounce),aria-busy对此毫无约束力 - 键盘焦点:如果刷新期间移除了焦点元素(比如列表清空),要主动
focus()到合适位置,否则键盘用户会“掉进空白”
兼容性提醒:所有现代浏览器都支持该属性解析,但旧版 NVDA(2018 前)或某些国产读屏对 aria-busy 感知较弱,所以不能只依赖它做唯一加载提示 —— 页面内仍需可见的 loading 文案或图标。
真正容易被忽略的是:当多个异步操作叠加作用于同一区域时(比如搜索中又点了排序),aria-busy 的设置/清除必须严格配对,否则可能卡在 "true" 状态不恢复,导致读屏永久跳过该区域。建议封装成带计数器的 busy 管理器,而非简单布尔切换。


















