<details>+<summary>是唯一省事且WCAG合规的方案;aria-expanded必须绑定在触发元素(如<button>)上,若加在<div>或<ul>等容器上,屏幕阅读器将无法感知状态变化。

直接用 <details> + <summary>,不用手写 aria-expanded —— 这是唯一既省事又 WCAG 合规的方案。手动实现容易漏掉焦点、状态不同步或 Safari 下静默不播报,不值得硬扛。
为什么不能把 aria-expanded 加在 div 或 ul 上
它必须绑定在触发交互的元素上,比如 <button>;如果写在被控制的内容容器(如 <ul class="submenu">)上,屏幕阅读器根本感知不到状态变化。常见错误写法:<button>菜单</button><ul aria-expanded="false">...——这等于没写。
手动实现时 setAttribute 必须传字符串 "true" 或 "false"
JavaScript 更新状态不是赋布尔值,而是显式设字符串属性:
-
btn.setAttribute('aria-expanded', isOpen ? 'true' : 'false')✅ -
btn.ariaExpanded = true❌(非标准,IE 和旧 Safari 不认) -
btn.setAttribute('aria-expanded', isOpen)❌(会写成true或false,无引号,不符合 ARIA 规范)
更推荐现代写法:btn.toggleAttribute('aria-expanded', isOpen),自动增删,语义更干净。
立即学习“前端免费学习笔记(深入)”;
aria-expanded 必须和 hidden / display: none 严格同步
光切 CSS 类或改 display 不够,屏幕阅读器只读属性值。状态错位会导致:视觉上展开但读屏器说“已收起”,或者反之。
- 先更新 DOM 可见性(例如
panel.hidden = !isOpen或panel.classList.toggle('is-hidden')) - 再调用
setAttribute更新aria-expanded - 别用
visibility: hidden或opacity: 0隐藏内容——它们仍留在可访问树里,AT 会误读
同时记得加 aria-controls="panel-id" 和对应面板的 role="region",否则辅助技术不知道这个按钮到底控制谁。
最麻烦的点不在代码本身,而在每次点击都要确认三件事:DOM 是否真可见、aria-expanded 是否已更新、焦点是否回到按钮或跳转到新内容首项——少一步,对屏幕阅读器用户就是不可用。



















