手风琴用 checkbox 而非 radio 是因需支持“全部收起”,checkbox 天然支持点击切换与 :checked 伪类闭环控制;radio 无法取消选中,除非 JS 干预。

手风琴折叠用 input[type="checkbox"] 而不用 radio 的原因
单个手风琴默认只展开一项?那确实该用 radio,但实际项目里几乎没人这么干——因为一旦用 radio,就无法「全部收起」。用户点开一个,再点一次就得保持展开态,而 radio 没有“取消选中”机制(除非 JS 干预)。checkbox 天然支持点击切换,配合 :checked 伪类就能干净实现「点开/收起」闭环。
常见错误现象:label 点击没反应、切换后内容不显示——大概率是 input 和 label 没绑定(缺 for 或 id),或 input 被设了 display: none 但没加 position: absolute; left: -9999px 类似的隐藏方式(部分浏览器对 display: none 的 :checked 状态识别不稳定)。
- 必须确保每个
input有唯一id,对应label[for] - 别用
visibility: hidden隐藏input,它仍占布局流,可能干扰相邻元素 - 移动端 Safari 对
label点击热区较窄,建议给label加padding或min-height
~ 选择器在手风琴结构里为什么比 + 更可靠
手风琴内容通常紧挨着 input,但中间常插 label(比如标题放 label,内容放 div)。这时如果写 input:checked + .content,会失效——因为 .content 不是 input 的**直接兄弟**,中间隔了 label。
~ 是后续兄弟选择器,只要在同一个父容器内、位于 input 后面的兄弟元素都匹配,容错性高得多。
立即学习“前端免费学习笔记(深入)”;
- 结构必须保证
input、label、内容容器都在同一层父元素下 - 别把内容块包进
label里(语义错误,且label内点击会反复触发 checkbox 切换) - Android WebView 旧版本对
~支持差,如需兼容 Android 4.x,得降级用 JS 或额外 wrapper
移动端动画卡顿?别直接用 height: auto 做过渡
CSS 过渡不能直接从 height: 0 到 height: auto,浏览器不知道 auto 对应多少像素,动画会跳变或失效。常见补救法是用 max-height 代替,但值设太小会截断内容,设太大又导致动画慢(比如设 max-height: 1000px,展开时要跑完 1000px 才停)。
更稳妥的做法:用 transform: scaleY() + overflow: hidden,性能更好,也不依赖具体高度。
-
transform触发 GPU 加速,比height过渡更顺滑 - 必须配
overflow: hidden,否则缩放时内容会溢出 - 注意
scaleY(0)会让子元素文字模糊(尤其是 iOS Safari),可加backface-visibility: hidden缓解 - 别对
transform做transition: all,只写transition: transform 0.3s ease
无障碍访问被忽略的三个硬伤
纯 CSS 手风琴最大的坑不是样式,是残障用户根本不知道这是可交互区域,或者屏幕阅读器读不出当前状态。光靠视觉隐藏 input 不够,还得补语义。
- 给
label加role="button"和aria-expanded属性,并用 JS 同步更新(CSS 无法改属性值) -
input本身不能display: none,得用position: absolute; clip: rect(0 0 0 0)这类可访问隐藏方式 - 内容区域必须加
role="region"和aria-labelledby指向对应label的id
没有 JS 就做不到完整无障碍——这是纯 CSS 方案绕不开的边界。如果项目要求 WCAG 2.1 AA,至少得用极简 JS 补上 ARIA 状态同步。


















