:checked伪类能替代JS做折叠面板,因其是原生表单状态伪类,配合checkbox/radio与label结构,通过兄弟/相邻选择器控制显示隐藏,支持无障碍且无需JS;需用clip隐藏input保留可访问性,用max-height+opacity过渡实现动画,radio组可实现单选手风琴效果。

为什么:checked伪类能替代JS做折叠面板
因为 :checked 是原生表单状态伪类,只要配合 <input type="checkbox"> 或 <input type="radio">,就能在不触发 JS 的前提下响应用户点击,并通过兄弟选择器(~)或相邻选择器(+)控制后续元素的显示/隐藏。它的触发是原子性的、无延迟的,且天然支持键盘焦点与屏幕阅读器(无障碍基础达标)。
必须用 checkbox + label + 隐藏 input 的结构
直接操作 <input> 本身不可见也不易点击,所以得靠 <label></label> 包裹标题来透传点击;同时要把 <input> 视觉隐藏但保留可访问性。常见错误是只用 display: none 或 visibility: hidden,这会让它完全脱离可访问流,键盘无法聚焦,屏幕阅读器也读不到。
- 用
position: absolute; clip: rect(0 0 0 0);隐藏<input>—— 保留语义和可聚焦性 -
<label></label>必须通过for属性或包裹方式与<input>绑定,否则点击无效 - 折叠内容必须紧跟在
<input>后面(用+),或在其后任意位置(用~),不能跨父容器
<input id="panel-1" type="checkbox"> <label for="panel-1">面板标题</label> <div class="panel-content">…</div>
:checked + 后续兄弟元素的显示控制逻辑
核心是利用 :checked 改变后续元素的 max-height 和 opacity,配合 CSS 过渡实现展开/收起动画。纯 display: none/block 无法过渡,所以必须避免。
- 初始状态:给
.panel-content设max-height: 0、overflow: hidden、opacity: 0 - 激活状态:
input:checked ~ .panel-content设max-height: 500px(需预估最大高度,或用fit-content配合height: auto在支持的浏览器中) - 过渡写在
.panel-content上:transition: max-height 0.3s ease, opacity 0.2s ease - 注意:Safari 对
max-height过渡有渲染 bug,建议加will-change: max-height缓解
radio 组实现单选折叠(类似手风琴)
如果多个面板要互斥展开,用 type="radio" 并统一 name 属性即可。每个 <input> 的 :checked 状态天然互斥,无需额外逻辑。
立即学习“前端免费学习笔记(深入)”;
- 所有 radio 共享同一个
name,比如name="accordion" - 每个
input控制自己对应的.panel-content,用唯一id/for绑定 - 初始全收起?确保没有一个 radio 设置
checked;默认展开第一个?加checked到第一个<input> - 注意:radio 不支持“再次点击收起”,如需该行为,仍得回退到 checkbox + JS
真正难的是内容高度不确定时的平滑过渡——max-height 必须设具体值,而 height: auto 无法过渡。多数项目用固定保守值(如 600px)够用;若必须精确,就得 JS 测高再写内联样式,那就不是纯 CSS 方案了。


















