:checked伪类通过控制同级input的勾选状态,利用相邻/通用兄弟选择器联动显隐内容区,配合max-height过渡实现纯CSS手风琴;需严格保证HTML兄弟结构、避免display、预估max-height值。

为什么:checked伪类能驱动手风琴展开收起
:checked 只作用于 <input type="checkbox"> 或 <input type="radio"> 元素,且仅在用户主动勾选/选中时为真。它本身不触发JS,但能联动控制兄弟或后代元素的样式——这正是纯CSS手风琴的核心机制:用隐藏的 checkbox 控制相邻 <details> 或 <div> 的显隐。
关键点在于:浏览器原生支持 :checked + selector(相邻兄弟选择器)和 :checked ~ selector(通用兄弟选择器),无需任何JS监听或状态管理。
HTML结构必须满足兄弟关系才能生效
如果 <input> 和内容区不在同一父容器下,或中间隔了其他非兄弟元素,:checked + .content 就完全不匹配。最稳妥的写法是让 <input> 紧邻 <label> 和目标内容块,并共用一个父容器。
-
<input id="faq1" type="checkbox">必须有唯一id -
<label for="faq1">的for值必须严格等于该id - 目标内容块(如
<div class="accordion-content">)必须是<input>的**下一个兄弟元素**,或使用~匹配后续所有符合条件的兄弟 - 避免把
<input>放在<label>内部——那样会失去对兄弟元素的控制力
折叠动画必须用max-height而非display
display: none 无法过渡(transition),强行加 transition: display 0.3s 无效。正确做法是用 max-height 配合溢出隐藏:
立即学习“前端免费学习笔记(深入)”;
.accordion-content {
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease-out;
}
input:checked ~ .accordion-content {
max-height: 500px; /* 设为足够容纳内容的最大值 */
}注意:max-height 的“足够大”值要预估内容高度,设太小会截断,设太大则收起时有延迟感;若内容高度差异极大,可改用 height + padding + opacity 组合过渡,但需 JS 测量——那就不是纯 CSS 了。
多个手风琴项互斥需要radio而非checkbox
默认用 checkbox 是多选的,点击一个展开、再点另一个,前一个不会自动收起。要实现单选互斥(类似原生 <details>),必须换成 radio:
- 所有 radio 的
name属性必须相同,例如name="accordion-group" - 每个 radio 的
id仍需唯一,对应各自的label[for] - 用
input[type="radio"]:checked ~ .accordion-content控制显隐 - 初始状态可用
input:checked设置默认展开项,或留空让全部默认收起
radio 方案天然支持单选,但失去“再次点击收起”的能力(除非加一个“关闭全部”的额外 radio);若需点击收起,还是得回到 checkbox + JS,或用 trick(比如双击事件无法纯CSS模拟)。
真正难的是内容高度不可预测时的平滑过渡,以及 Safari 对 max-height 过渡的渲染抖动——这些没法靠 :checked 解决,得靠边界处理或降级方案。


















