:checked伪类仅响应用户点击触发的真实表单状态变更,不响应JS修改或初始属性;通过:checked + label或:checked ~ .target将状态透传至后续同级元素,要求复选框必须是目标节点的前序同级元素且不能为祖先。

为什么:checked伪类能控制开关状态
:checked 只匹配被用户主动勾选的 <input type="checkbox"> 或 <input type="radio"> 元素。它不响应 JavaScript 修改的 checked 属性,也不管初始 checked 是否为 true —— 仅当用户点击触发真实表单状态变更时才生效。这是纯 CSS 开关能“记住”状态的根本前提。
如何用:checked + 相邻兄弟选择器切换关联节点显示
核心是利用 input:checked + label 或 input:checked ~ .target 这类组合器,把复选框的状态“透传”到后续元素上。关键约束有三个:
- 复选框必须是目标节点的**前序同级元素**(不能嵌套在父容器里再找子元素)
- 若用
+,目标节点必须紧邻其后;若用~,可跨多个同级节点 - 目标节点不能是复选框的父级或祖先,CSS 无法向上选择
常见结构示例:
<input type="checkbox" id="switch">
<label for="switch">开关</label>
<div class="panel">内容区</div>
<style>
#switch:checked ~ .panel { display: block; }
#switch:not(:checked) ~ .panel { display: none; }
</style>
实现视觉开关按钮时容易忽略的 HTML 结构陷阱
很多人想让点击 label 就触发 checkbox 切换,但忘了加 for 属性或没用 id 匹配,导致点击无反应。还有人把 checkbox 放在 label 内部又设 display: none,结果 Safari 下部分版本会丢掉焦点逻辑。
立即学习“前端免费学习笔记(深入)”;
- 务必确保
<input id="x">和<label for="x">的 id 完全一致(区分大小写) - 避免对 checkbox 使用
visibility: hidden,推荐用position: absolute; left: -9999px或clip-path: inset(100%)隐藏但保留可访问性 - 不要用
pointer-events: none在 checkbox 上,否则 iOS Safari 会拒绝触发 :checked
:checked 控制多节点时的性能与可维护边界
用 ~ 选择器可以影响多个后续兄弟节点,但一旦结构变深或插入新元素,样式就可能意外失效。更严重的是:浏览器对 :checked 后续选择器的重排计算是实时的,如果目标节点很多(比如上百个 .item),切换瞬间会有明显卡顿。
- 单页中建议控制在 20 个以内受控节点,超出请考虑用 JS 切 class
- 避免嵌套使用
:checked ~ .a ~ .b ~ .c,层级越深,CSS 引擎匹配越慢 - 如果需要“反向控制”(比如 checkbox 未选中时才显示某区域),直接写
:not(:checked) ~ .hidden-when-on,别试图用 JS 模拟
真正难的不是写对那几行 CSS,而是把 checkbox 放在 DOM 正确位置、让它和交互目标保持稳定兄弟关系——这个结构一旦错,后面所有样式都白搭。


















