必须用aria-live="polite"当内容动态插入且需主动告知用户时,如AJAX加载列表、表单提交反馈;须作为独立容器append内容,禁用innerHTML替换,避免与aria-hidden混用。
ARIA 不是语义的替代品,而是语义缺失时的精准补丁;用对地方能解决原生 HTML 无法表达的动态状态、自定义结构和跨元素关系问题,用错反而让屏幕阅读器彻底“失明”。
当内容通过 JavaScript 动态插入(比如 AJAX 加载列表、表单提交反馈、实时通知),且用户需要被主动告知变化时才用。它不改变 DOM 结构,只向辅助技术广播更新事件。
aria-hidden="true" 控制区域显隐——隐藏后屏幕阅读器完全感知不到新内容<div aria-live="polite"></div> 作为独立容器,JS 往里 appendChild 或 textContent 赋值,而非替换整个 innerHTMLaria-live="assertive" 除非是错误弹窗或中断性提示,否则会打断当前朗读,引发用户焦虑aria-live,需 fallback 到焦点强制移动(el.focus())+ tabindex="-1"
仅加 role="listbox" 是无效的——浏览器会报“缺少必需子角色”,屏幕阅读器直接跳过整个区域。
role="listbox" 容器内所有选项必须是 role="option"(不能是 <div> 或 <li>)aria-haspopup="listbox" 和 aria-expanded="false",JS 打开/关闭时必须同步更新该值tabindex="0" 暴力推进;要用 aria-activedescendant 指向当前高亮项的 ID,并监听 ArrowUp/ArrowDown 手动切换innerHTML = 替换下拉内容,aria-activedescendant 会断开指向,必须改用 appendChild 或 insertAdjacentElement
三者少一个,屏幕阅读器就可能把它当成普通浮层忽略——尤其 aria-modal="true" 是真正隔离背景的关键。
立即学习“前端免费学习笔记(深入)”;
role="dialog" 只声明类型,不阻止背景朗读;aria-modal="true" 才切断可访问树中背景节点(旧版 IE 不支持,需 fallback 到 inert 或焦点锁定)aria-labelledby 必须指向一个**真实存在、已渲染、有语义的可见标题元素**(如 <h2 id="modal-title">确认删除</h2>),不能是空 <span> 或 JS 生成后未插入 DOM 的节点focus() 主动将焦点移到首个可聚焦元素(通常是取消按钮或标题),否则键盘用户卡在背景<body> 加 aria-hidden="true"——这会让整个页面从可访问树中消失;正确做法是给背景容器加 inert 或 tabindex="-1" + 焦点捕获用 aria-describedby 指向分组标题,只能附加一次描述文本,无法建立结构化隶属关系;用户逐单元格浏览时,上下文极易丢失。
<table>,外层用 <section> 包裹并设 aria-labelledby 指向该区块标题<h2 id="sec-hospitalization">Hospitalization</h2>),再配合 headers 属性让单元格明确归属aria-hidden="true" 控制表格分组显隐——它不会移除焦点能力,键盘用户仍可能卡在不可见行上<th> 必须带 scope(col 或 row),否则屏幕阅读器无法理解行列关系最易被忽略的点:ARIA 本身不提供键盘导航逻辑、不修复焦点流断裂、也不让非交互元素自动可聚焦——它只是“说清楚这是什么”,而“怎么操作”得靠语义 HTML 和 JS 行为控制来补全。