纯html+css可用实现无js手风琴菜单,现代浏览器原生支持、语义化且无障碍友好;需用css模拟箭头、避免嵌套交互元素、多选互斥需js补充。

手风琴菜单(Accordion)用纯 HTML + CSS 就能实现,不需要 JS 也能展开收起,关键在 <details></details> 和 <summary></summary> 标签的组合用法。
用 <details></details> + <summary></summary> 实现无 JS 手风琴
现代浏览器(Chrome 12+、Firefox 49+、Safari 6+、Edge 79+)都支持原生手风琴语义化标签。它默认可折叠,点击 <summary></summary> 触发展开/收起,且自带 ARIA 属性,无障碍友好。
实操建议:
-
<details></details>是容器,每个独立面板一个;<summary></summary>必须是它的第一个子元素 - 加
open属性让面板默认展开:<details open></details> -
<summary></summary>内容会自动渲染为可点击标题,不需额外事件绑定 - 避免在
<summary></summary>里嵌套交互元素(如按钮、链接),否则部分浏览器可能触发两次展开
<details><summary>常见问题</summary><p>这里是折叠内容……</p> </details>
CSS 控制样式和箭头图标
原生 <details></details> 没有默认箭头,也不支持直接用 ::before 伪元素给 <summary></summary> 加图标(因为它是替换元素)。得靠 list-style 或背景图模拟。
实操建议:
- 清除默认列表样式:
summary { list-style: none; } - 用
background-image+background-position实现箭头,并通过[open] summary切换旋转状态 - 禁用默认下划线(如果用了
<a></a>包裹<summary></summary>):必须设text-decoration: none - 不要对
<details></details>设固定height,否则动画会卡顿;用max-height+transition做平滑展开(但注意:原生<details></details>不触发transition,需 JS 补充或改用grid-template-rows动画)
需要多选/手风琴互斥?得加 JS
原生 <details></details> 默认支持多开,无法限制“只允许一个展开”。如果业务要求单开互斥(即打开一个时自动关闭其他),就必须用 JS 监听 toggle 事件并手动控制 open 属性。
实操建议:
- 监听所有
<details></details>的toggle事件(注意:该事件不冒泡,得逐个绑定) - 在事件回调中遍历同级
<details></details>,对非当前项调用.removeAttribute('open') - 避免用
click代替toggle,否则键盘空格/回车展开时逻辑失效 - 若用框架(如 React),注意服务端渲染时
<details open></details>可能导致水合不一致,需在useEffect中同步状态
IE 或老版本 Safari 怎么兼容?
<details></details> 在 IE 完全不支持,Safari 5.1–6.0 也无支持。如果必须兼容,别强行 polyfill,直接降级为 JS 驱动方案更可靠。
实操建议:
- 用
if (!('open' in document.createElement('details')))检测原生支持 - 不推荐用
display: block/none切换——会导致屏幕阅读器跳过内容;应改用aria-expanded+aria-hidden手动管理可访问性 - 动画优先用
height: 0 → height: auto配合overflow: hidden,但注意height: auto无法过渡,得先用getBoundingClientRect()获取真实高度再设内联style.height - 移动端注意
touch-action: manipulation提升点击响应速度
真正难的不是实现展开收起,而是处理键盘操作(Tab 进入、空格切换)、焦点管理、屏幕阅读器播报顺序,以及在 SSR/CSR 混合场景下保持 DOM 状态一致——这些细节比写个 for 循环容易被忽略。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











