原生 和 是最轻量、语义准确且无障碍友好的手风琴实现方案,现代浏览器原生支持,无需 js 或 css 框架; 必须为 的首个子元素,用 ::marker 自定义箭头,避免破坏语义。

用 details 和 summary 最快实现原生手风琴
不用 JS、不引 CSS 框架,现代浏览器(Chrome 12+、Firefox 49+、Safari 6.1+)直接支持。这是最轻量、语义最准、无障碍友好的方案。
常见错误是手动写 div + click 监听 + 切换 display,既重复造轮子,又漏掉键盘操作(如回车展开)、屏幕阅读器标记等关键细节。
实操建议:
-
<details></details>默认收起,加open属性可默认展开 -
<summary></summary>必须是<details></details>的第一个子元素,否则无效 - 点击
<summary></summary>文本或其空白区域都会触发展开/收起,无需额外绑定事件 - 若需自定义箭头图标,用
::marker伪元素控制,不要用span套图标——会破坏语义和焦点顺序
<details><summary>常见问题</summary><p>这里是折叠内容……</p> </details>
需要兼容 IE 或旧版 Safari?用 aria-expanded + aria-controls 手动控制
IE 完全不支持 details,旧版 Safari(details 的 open 属性变更监听不灵敏。此时必须退回到 JS 控制的 DOM 方案,但不能只改 style.display —— 那样对屏幕阅读器不可见。
关键点是正确同步 ARIA 状态:
- 初始状态:面板
aria-hidden="true",按钮aria-expanded="false",且aria-controls指向面板 ID - 点击后:切换按钮的
aria-expanded,同时切换面板的aria-hidden和hidden属性(hidden是 HTML 原生属性,比display: none更语义化) - 务必用
addEventListener('click', ...),别用onclick行内属性——不利于维护和测试
示例逻辑片段:
const btn = document.querySelector('[aria-controls="panel-1"]');
const panel = document.getElementById('panel-1');
btn.addEventListener('click', () => {
const expanded = btn.getAttribute('aria-expanded') === 'true';
btn.setAttribute('aria-expanded', !expanded);
panel.setAttribute('aria-hidden', expanded);
panel.toggleAttribute('hidden', !expanded);
});
动画过渡失效?别只设 max-height,要配合 overflow 和 transition
纯 CSS 动画手风琴最容易卡在“收起时内容突然消失”或“展开时高度跳变”。根本原因是 height: auto 无法参与 CSS 过渡。
解决方案是用 max-height 替代 height,但有严格前提:
- 面板容器必须设
overflow: hidden,否则内容会溢出 -
max-height的目标值要大于内容实际高度(比如设max-height: 500px),不能写max-height: 0→max-height: auto(auto 不触发过渡) - 过渡必须写在面板上,而不是按钮上:
transition: max-height 0.3s ease, opacity 0.2s ease - 收起时,
max-height设为 0 后,需在transitionend后再设display: none(如果真需要)——但更推荐全程用hidden属性控制可访问性
多个面板互斥(单选模式)?靠 JS 清除其他 open 状态或重置 ARIA
原生 details 默认是多开的,要实现“点一个、关其他”,必须用 JS 干预。但注意:不能简单遍历所有 details 并设 open = false,这会打断用户正在操作的流程(比如快速连续点击)。
更稳妥的做法:
- 监听
toggle事件(details元素原生支持),而非click - 在当前
details触发toggle后,遍历其他同组details,仅关闭那些open === true的 - 如果是 ARIA 方案,同步清除其他按钮的
aria-expanded="true"和对应面板的aria-hidden="false" - 避免在
toggle回调里直接操作 DOM 样式,优先用属性变更驱动 CSS(例如用[data-state="open"]配合 CSS)
容易被忽略的是:键盘用户按 Space 或 Enter 也会触发 toggle,所以必须监听这个事件,而不是只绑 click。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











