应统一用 aria-expanded 属性判断展开状态,因其语义明确、无障碍友好且不受 CSS 动画或中间态干扰;读取时需用 getAttribute('aria-expanded') === 'true',设置时须同步更新属性与内容显隐。

如何用 click 事件配合 aria-expanded 判断展开状态
直接读取 aria-expanded 属性比检查 class 或 height 更可靠,尤其在无障碍和动态渲染场景下。它天然支持屏幕阅读器,且不会因 CSS 动画或 JS 中间态(比如正在过渡)产生误判。
实操时注意:该属性值是字符串 "true" 或 "false",不是布尔值,别直接写 if (el.ariaExpanded) —— 这会永远为 true(因为非空字符串转布尔为真)。
- 设置初始状态:
aria-expanded="false"(默认收起),对应内容容器加hidden属性或display: none - 点击后手动切换:
button.setAttribute('aria-expanded', current === 'true' ? 'false' : 'true') - 读取状态统一用:
button.getAttribute('aria-expanded') === 'true'
details/summary 原生方案是否够用?
够用,但有硬性限制:无法自定义展开/收起动画、不支持嵌套、summary 必须是第一个子元素。如果你只需要基础交互且不关心动效,它是零 JS、语义正确、无障碍友好的首选。
常见误用:给 details 加 open 属性后,再用 JS 监听 toggle 事件,却忘了这个事件**不带冒泡**,也不能阻止默认行为 —— 它只是通知状态变了,不能干预开关逻辑。
立即学习“前端免费学习笔记(深入)”;
将 Markdown 文章转换为微信公众号兼容的纯 HTML 格式。当用户要求"转成微信格式"、"生成公众号文章 HTML"、"排版到微信草稿箱"、"微信粘贴格式"时触发。输出带内联样式的纯 HTML,微信编辑器可直接渲染,无需额外适配。支持标题、段落、列表、粗体、行内代码、表格、引用块、代码块、配图的完整转换。
- 监听方式必须是:
details.addEventListener('toggle', handler),不是click - 判断当前是否展开:用
details.open(布尔值),不是查属性 - 想禁用用户手动切换?只能加
disabled到summary,但会丢失键盘焦点能力
用 classList.toggle() 同步控制样式与状态的坑
很多人用 el.classList.toggle('is-open') 更新 class,再靠 CSS 控制显隐,但忘记同步更新 aria-expanded —— 这会导致屏幕阅读器读错,也使 JS 后续判断失效。
关键点在于:class 和 ARIA 属性必须**严格同步更新**,顺序不重要,但不能只做一半。
- 推荐写法:
const isOpen = button.getAttribute('aria-expanded') === 'true'; button.setAttribute('aria-expanded', isOpen ? 'false' : 'true'); content.hidden = isOpen; - 避免只改 class:
el.classList.toggle('expanded')却漏掉aria-expanded更新 - 不要依赖 class 名判断状态,CSS 类名可能被复用、重命名或受其他 JS 干扰
React/Vue 等框架中状态不同步的典型表现
在组件内用 useState 或 ref 管理展开状态,但没把状态同步到 DOM 属性上,就会出现「JS 认为已展开,DOM 属性仍是 false」—— 这让外部脚本、E2E 测试或无障碍工具完全不可知真实状态。
例如 React 中只写 {isOpen && <div>...</div>},却不给 toggle 按钮设 aria-expanded={isOpen.toString()},就等于放弃语义化。
- Vue 模板中务必绑定:
:aria-expanded="isOpen.toString()" - React 中 JSX 属性要显式写:
aria-expanded={String(isOpen)}(不能用布尔值,否则 React 会忽略false) - 服务端渲染(SSR)时,初始
aria-expanded必须和服务端状态一致,否则 hydration 会出警告
class,一处读 hidden,一处读 aria-expanded,最后谁都不认谁。统一锚定 aria-expanded,既是规范要求,也是减少歧义的最简路径。


















