必须用details+summary,因其是HTML5原生折叠组件,自带展开/收起状态、键盘操作(Space/Enter)及屏幕阅读器支持,语义正确且无需JS;其他方案如checkbox模拟存在可访问性硬伤。

手风琴折叠效果不用 JS 也能做,纯 CSS 完全可行,但必须用 details + summary,其他方案(比如用 checkbox 或 radio 模拟)在可访问性和语义上都存在硬伤。
为什么必须用 details 和 summary?
这是 HTML5 原生支持的折叠组件,自带展开/收起状态、键盘操作(Space/Enter)、屏幕阅读器支持。用 div + aria-expanded 等手动模拟,不仅代码量翻倍,还容易漏掉焦点管理或状态同步。
常见错误现象:TypeError: Cannot read property 'toggle' of null —— 这类报错往往来自试图用 JS 控制非交互元素,其实根本不需要 JS。
-
details默认是闭合的,加open属性可默认展开 -
summary必须是details的第一个子元素,否则部分浏览器不识别 - 不能把
summary包在其他标签里(比如div),否则点击无效
如何用 CSS 控制展开动画?
details 本身不支持 height 过渡(因为高度是自动计算的),所以得绕开:用 max-height + overflow 模拟,或者改用 clip-path / transform 避免高度估算。
立即学习“前端免费学习笔记(深入)”;
推荐用 clip-path 方案,兼容性足够(Chrome 71+、Firefox 63+、Safari 15.4+),且无需预估内容高度:
details {
overflow: hidden;
}
details[open] {
clip-path: polygon(0 0, 100% 0, 100% 100%, 0 100%);
transition: clip-path 0.3s ease-out;
}
details:not([open]) {
clip-path: polygon(0 0, 100% 0, 100% 0, 0 0);
}
- 别用
height: 0+transition,内容高度未知时无法精确设置目标值 - 如果必须支持老版本 Safari,可用
max-height,但需设一个“足够大又不太大”的值,比如max-height: 500px -
transition只写在details上,不要分开写在[open]和:not([open])里,否则可能触发两次重绘
怎么让多个手风琴互斥(单选模式)?
CSS 本身没有“组控制”能力,details 是独立状态。真要单选,必须用 JS 监听 toggle 事件并手动关闭其他项。
但如果只是视觉上模仿(比如加个图标旋转、背景色切换),CSS 能做到:
details[open] summary::after {
transform: rotate(180deg);
}
details summary::after {
content: "▼";
display: inline-block;
margin-left: 8px;
transition: transform 0.2s;
}
- 图标方向变化靠
transform,不是换两个不同字符,避免布局抖动 - 所有
details共享同一组样式即可,无需额外 class 区分 - 如果项目明确要求单选且需键盘导航支持,JS 不可省略——这时候 CSS 只负责视觉反馈
真正麻烦的不是怎么展开,而是内容区域的 padding/margin 如何随展开收缩自然过渡;clip-path 方案能绕过这个问题,但要注意内层元素如果有 position: absolute,可能被裁剪意外截断。


















