手风琴折叠必须用 <input type="checkbox"> 而非 <details>,因 :checked 仅对其和 radio 生效,且需通过 id/for 关联 label 与 checkbox,再用 :checked + label + .accordion-content 控制显隐;动画须用 max-height + overflow: hidden 配合 transition,禁用 display;单选靠 name 统一 + ~ 后代选择器实现纯 CSS 互斥;移动端需增大点击区域、避免依赖 :focus、处理 iframe 事件拦截;max-height 值需预估,fit-content 尚未广泛支持。

手风琴折叠必须用 <input type="checkbox"> 而不是 <details>
因为 :checked 只对 <input type="checkbox"> 和 <input type="radio"> 生效,<details> 用的是 :open,不兼容老浏览器且无法和兄弟元素联动。手风琴需要点击标题控制内容显隐,而纯 CSS 实现依赖“隐藏 checkbox + label 关联 + :checked 触发兄弟选择器”这个链路。
常见错误是直接套用 <div> 或 <button>,结果样式完全不响应——:checked 不会作用在它们身上。
- 每个折叠项必须包含一个
<input type="checkbox" id="accordion-1">(id唯一) - 对应标题用
<label for="accordion-1">,点击即触发勾选/取消 - 折叠内容用
<div class="accordion-content">,并通过input:checked + label + .accordion-content或类似兄弟选择器控制显隐
display: none 和 max-height: 0 的取舍直接影响动画是否生效
:checked 本身不支持过渡,但你可以对它控制的后续元素做 transition。问题在于:display 属性无法过渡,所以直接写 display: none → display: block 会导致突兀切换,没有动画。
正确做法是用 max-height 搭配 overflow: hidden:
立即学习“前端免费学习笔记(深入)”;
- 默认状态设
max-height: 0; overflow: hidden; opacity: 0; -
:checked + label + .accordion-content设max-height: 300px; opacity: 1;(值要略大于内容实际高度) - 加
transition: max-height 0.3s ease, opacity 0.2s ease;
注意:如果内容高度差异大,固定 max-height 值可能不够或过高;此时可改用 height: auto + transform: scaleY() 组合,但需 JS 配合测高——纯 CSS 就得接受预估高度。
单选手风琴(一次只开一个)靠 name 属性和 :not(:checked) 配合实现
原生 checkbox 是多选的,要模拟 radio 行为(点一个关其他),不能靠 JS。技巧是:所有 checkbox 共享同一个 name(比如 name="accordion"),虽然 HTML 规范里 checkbox 不按 name 分组,但结合 CSS 选择器可以“视觉上”实现互斥。
关键在选择器写法:
input[name="accordion"]:checked + label + .accordion-content {
/* 当前展开 */
}
input[name="accordion"]:not(:checked) + label + .accordion-content {
/* 其他全部收起 */
}但这只在 DOM 顺序严格时有效。更稳的方式是把所有 .accordion-content 放在同一个父容器内,并用 input:checked ~ .accordion-content(后代选择器)统一控制,再单独给当前项加例外:
- 先写
.accordion-content { max-height: 0; } - 再写
input:checked ~ .accordion-content { max-height: 0; }(默认全关) - 最后写
input:checked + label + .accordion-content { max-height: 300px; }(仅当前开)
移动端点击区域小、Safari 对 :checked + label 的 focus 状态有延迟
iOS Safari 在点击 <label> 时,有时 checkbox 状态更新滞后一帧,导致动画闪一下或卡住。这不是 bug,是 Safari 对表单控件 focus/checked 状态的渲染优化策略。
解决方法很实际:
- 确保
<label>包裹文字,且padding≥ 12px,避免点击边缘失效 - 加
cursor: pointer和-webkit-tap-highlight-color: transparent提升响应感 - 不要依赖
:focus做交互反馈,改用:active或伪元素::after模拟按下态 - 如果内容含 iframe 或第三方组件,它们可能拦截 pointer 事件——把
label的z-index提高并加position: relative
真正难调的不是结构,而是那个 max-height 的临界值:设小了内容被截断,设大了动画慢半拍。最好用 fit-content 替代方案,但目前只有 Firefox 支持 max-height: fit-content,所以还是得手动量。


















