aria-expanded 是状态快照,仅用于可交互控件(如button)触发内容显隐时,须与真实状态严格同步,并配套 aria-controls 指向目标ID,服务端渲染需初始即写入。

aria-expanded 不是开关,而是状态快照——它必须和元素真实展开/折叠状态严格同步,否则屏幕阅读器会读错,用户会迷失。
什么时候必须用 aria-expanded
只在「可交互的控件触发内容显隐」时才需要:button、a 或带 role="button" 的元素控制另一个区域(如 div、section)的显示/隐藏。纯 CSS :hover 展开、自动轮播、无交互的静态展开,都不该加。
- 常见场景:导航下拉菜单、手风琴面板(accordion)、模态框开关按钮
- 错误用法:
div自己标aria-expanded="true"(它不是控件) - 替代方案:如果被控制的内容区用了
role="region"或role="tabpanel",且有明确标题关联,有时可省略aria-expanded,但加了更稳妥
aria-expanded 的值必须实时更新
不能只在初始化时设一次。JS 控制显隐时,aria-expanded 要和 hidden 属性、display 样式、实际 DOM 可见性完全一致。
- 展开内容前:
button.setAttribute('aria-expanded', 'true'),再显示内容 - 收起内容前:
button.setAttribute('aria-expanded', 'false'),再隐藏内容 - 千万别反着来——先改样式再改属性,屏幕阅读器可能读到“已展开”但内容还没出现
- 如果用
classList.toggle()切换.is-open类,记得同步更新属性:btn.setAttribute('aria-expanded', btn.classList.contains('is-open'))
别漏掉 aria-controls 配套使用
aria-expanded 单独存在意义有限。必须配合 aria-controls 指向被控制区域的 id,才能建立语义关联。
立即学习“前端免费学习笔记(深入)”;
- 按钮写法:
<button aria-expanded="false" aria-controls="panel-1">详情</button> - 对应内容区:
<div id="panel-1" hidden>...</div> - 注意:
aria-controls的值必须和目标元素id完全一致(区分大小写、不可含空格) - 没配
aria-controls时,NVDA、VoiceOver 可能只读“已展开”,却不说明“展开了什么”
最常被忽略的一点:服务端渲染或 SSR 页面中,如果首屏内容默认展开,HTML 模板里就得直接写出 aria-expanded="true" 和 aria-controls="xxx",而不是等 JS 加载后再补——否则首屏对辅助技术就是“失联”的。


















