aria-expanded 必须与面板实际状态实时同步,展开时设为"true"、收起时设为"false",配合 aria-controls 和 role="region" 使用;优先采用原生 details/summary,仅在必要时手动实现并严格保证状态同步。

aria-expanded 必须和面板实际状态实时同步
它不是“设一次就完事”的装饰属性,而是屏幕阅读器判断按钮是否已展开的唯一依据。如果 JavaScript 控制了 hidden 或 max-height 但没更新 aria-expanded,用户会听到“已折叠”却看到内容开着,甚至无法再次触发操作。
- 展开时必须设为
aria-expanded="true",收起时必须设为aria-expanded="false" - 不能只在初始化时写死,比如
<button aria-expanded="false">然后不管了 - 切换逻辑里每一步都要检查真实 DOM 状态:用
element.offsetHeight > 0或!element.hasAttribute('hidden')判断,再据此设置属性 - 避免用
display: none配合aria-expanded—— 这种组合对屏幕阅读器无效,因为display: none会让元素彻底脱离可访问树
按钮必须是语义化可聚焦元素,不能用 div+role="button"
只有原生 button、a(带 href)、input 等才能自然获得键盘焦点、回车/空格触发,且浏览器会自动把 aria-expanded 和其关联行为绑定起来。
- 别写
<div role="button" tabindex="0" aria-expanded="false">标题</div>—— 它不响应空格键,也不保证焦点管理正确 - 用
<button type="button" aria-expanded="false">是最稳妥的选择 - 如果必须用链接,确保有
href="#"并在 click 里event.preventDefault(),否则页面会跳转
必须配合 aria-controls 和 role="region"
aria-expanded 单独存在没有意义,它需要明确告诉辅助技术:“我控制的是哪个区域”,而这个关联靠 aria-controls 和 role="region" 共同完成。
使用 PptxGenJS 和 Python 解析,将结构化的 HTML/CSS 幻灯片内容转换为原生、可编辑的 PowerPoint(.pptx)演示文稿。
- 按钮上加
aria-controls="panel-1",对应面板的id="panel-1" - 面板容器必须设
role="region",否则屏幕阅读器不知道这是个独立的内容区块 - 推荐额外加上
aria-labelledby="panel-1-header"(假设按钮 id 是panel-1-header),让面板能反向被标题识别 - 别把
aria-expanded写在面板上 —— 它只属于触发控件
details/summary 是更优解,别硬套 aria-expanded
如果你只是想实现基础折叠/展开,<details> 已经内置了完整的可访问性支持:自动管理 aria-expanded、键盘操作、toggle 事件、无需 JS 就能工作。强行用 div + aria-expanded 反而容易漏掉焦点流转或状态不同步。
立即学习“前端免费学习笔记(深入)”;
- 写法极简:
<details><summary>标题</summary>内容</details> - 默认展开加
open属性:<details open> - 需要自定义样式?用
details[open] > summary和summary::marker - 仅当需要动画过渡、多面板联动、或兼容 IE 时,才考虑手动方案 —— 但此时
aria-expanded同步就是第一道生死线
aria-expanded="true",而是确保每次 DOM 变更后它都还对。很多人在动画结束回调里忘了更新,或者用 CSS visibility 隐藏却误判了“是否展开”。状态同步必须和视觉变化严格对齐,差一帧,无障碍就断了。


















