手风琴折叠必须用 而非 ,因 :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></details>
因为 :checked 只对 <input type="checkbox"> 和 <input type="radio"> 生效,<details></details> 用的是 :open,不兼容老浏览器且无法和兄弟元素联动。手风琴需要点击标题控制内容显隐,而纯 CSS 实现依赖“隐藏 checkbox + label 关联 + :checked 触发兄弟选择器”这个链路。
常见错误是直接套用 <div> 或 <code><button></button>,结果样式完全不响应——:checked 不会作用在它们身上。
- 每个折叠项必须包含一个
<input type="checkbox" id="accordion-1">(id唯一) - 对应标题用
<label for="accordion-1"></label>,点击即触发勾选/取消 - 折叠内容用
<div class="accordion-content">,并通过 <code>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></label>时,有时 checkbox 状态更新滞后一帧,导致动画闪一下或卡住。这不是 bug,是 Safari 对表单控件 focus/checked 状态的渲染优化策略。解决方法很实际:
- 确保
<label></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,所以还是得手动量。 - 默认状态设











