首选原生 details 元素实现手风琴效果,语义正确、键盘可访问、无需 JS;但 open 属性切换不触发动画,无法实现高度渐变;若需动画,须改用 checkbox + label 模拟。

用 details 和 summary 标签最简单,但得知道它不支持动画
纯 CSS 实现手风琴效果,首选原生 details 元素 —— 它自带折叠/展开状态、键盘可访问、语义正确,且无需 JS。但关键限制是:浏览器对 details 的 open 属性切换不触发 CSS 过渡(transition),所以无法直接实现高度渐变动画。
实操建议:
- 如果项目只要求功能可用、无障碍友好、且不需要展开收缩动画,直接用
<details><summary>标题</summary>内容</details>,加几行 CSS 控制样式即可 - 若必须有高度过渡效果,就得放弃
details,改用checkbox+label模拟状态,靠:checked控制max-height或opacity动画 -
details在 Safari 旧版本(summary::marker 自定义,IE 完全不支持 —— 需要兼容时务必测试
用 checkbox + :checked 实现带过渡的手风琴
这是目前最稳定、纯 CSS、可动画的方案:利用隐藏的复选框控制显隐,配合 label 触发,再用 max-height 过渡模拟高度变化。
常见错误现象:
立即学习“前端免费学习笔记(深入)”;
- 直接对
height做transition:无效,因为height: auto无法过渡 -
max-height设太小(如max-height: 200px),内容超长时会被截断 - 没设
overflow: hidden,展开时内容会溢出并撑开布局
实操建议:
- 给内容区设
max-height: 0+overflow: hidden,:checked时设一个足够大的值(如max-height: 500px),确保所有可能内容都能容纳 - 过渡写在
max-height上,时间建议0.3s,缓动用cubic-bezier(0.4, 0, 0.2, 1)更自然 -
label必须紧邻input[type="checkbox"],或用for绑定 ID,否则点击无效
示例结构片段:
<input type="checkbox" id="accordion-1"> <label for="accordion-1">常见问题</label> <div class="accordion-content"> <p>这里是折叠的内容…</p> </div>
CSS 关键部分:
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
#accordion-1:checked ~ .accordion-content {
max-height: 500px;
}
为什么不用 visibility 或 opacity 替代?
单纯用 visibility: hidden 或 opacity: 0 虽然能过渡,但它们不改变文档流高度 —— 折叠后空白区域还在,手风琴“收不回去”,用户体验断裂。
使用场景判断:
- 仅需视觉淡入淡出(比如 FAQ 卡片悬浮展开),
opacity+pointer-events可行,但不算真正“折叠” - 需要真实收起空间、保持下方内容上移,必须靠
max-height或height(后者需预知高度) -
transform: scaleY(0)看似可行,但缩放会模糊文字、影响可访问性,且无法与高度过渡自然衔接
移动端点击区域和可访问性容易被忽略的点
手风琴在手机上常因点击区域太小、响应迟钝被误判为“失效”。这不是 CSS 能单独解决的,但 CSS 配合 HTML 能规避多数问题:
-
label必须包裹文字,且至少设min-height: 44px(iOS 推荐最小触控尺寸) - 避免只用伪元素(如
::after)做展开箭头并绑定事件 —— 屏幕阅读器无法聚焦,也无法键盘操作 - 用
aria-expanded和aria-controls手动同步状态(即使用了checkbox),否则 VoiceOver/NVDA 读不出当前是否展开 - 不要依赖
:hover做核心交互,移动端无 hover;所有状态切换必须基于:checked或details[open]
复杂点在于:纯 CSS 方案无法监听“展开完成”事件,所以没法在动画结束时自动 focus 内容区 —— 如果内容里有表单或链接,用户还得手动滑动查找。这点 JS 方案反而更可控。


















