纯CSS全选需全选框在DOM中位于所有子项之前,用:checked ~ .item控制;label包装会破坏兄弟关系;半选状态必须JS设置indeterminate;超200项时建议改用JS批量操作。

用:checked配合兄弟选择器控制全选/反选逻辑
纯CSS实现多选框全选切换,关键不在JavaScript,而在利用:checked状态和~(通用兄弟选择器)把「全选框」的状态“广播”给其他复选框。但必须注意DOM顺序:全选框必须出现在所有目标子项之前,否则~无法向上匹配。
- HTML结构必须是:
→ 然后紧接所有 - 不能用
+(相邻兄弟),因为子项之间不相邻;~才支持跨多个兄弟节点匹配 - 如果子项被包裹在或
里,而没和全选框同级,:checked ~ .item就完全失效为什么:checked + label组合容易失效
很多人想用
包装子项来提升点击区域,结果发现全选后子项没变状态——这是因为:checked只作用于本身,label只是交互代理,不参与CSS状态链。CSS规则里写#select-all:checked ~ label > input.item看似合理,但浏览器不认为label是可被~选中的“兄弟”,它只是容器。- 正确做法:让所有待控的
和#select-all处于同一父级、无嵌套 - 若必须用
label,把input放在label内,但CSS仍只能通过:checked ~ label input.item去捕获,前提是label本身是#select-all的后续兄弟 - 移动端点透问题:某些安卓WebView下
label点击可能不触发:checked重绘,需加touch-action: manipulation
反选和半选状态无法纯CSS表达
:checked只有“已勾选”和“未勾选”两种状态,没有“部分勾选”。所以当用户手动勾选部分子项后,全选框无法自动变成“半选”(—)。这个视觉反馈必须靠JS驱动indeterminate属性,CSS里:indeterminate虽存在,但无法通过用户操作自动触发,只能由JS显式设置。-
能显示短横线,但这个属性不会随子项变化自动更新 - 如果你看到“纯CSS实现半选”,那一定是用伪元素+背景图模拟的视觉假象,实际
checked状态仍是false,点击后行为会错乱 - 真实业务中,只要涉及“同步状态”,就必须监听
change事件并更新indeterminate和全选框的checked
兼容性与性能边界在哪
IE9+支持
:checked,但IE11及更早版本不支持:indeterminate;Safari 15.4之前对~在复杂嵌套下的匹配有偶发bug。更重要的是性能:当子项超过200个,CSS引擎遍历兄弟节点会明显卡顿,尤其在低配安卓设备上。- Chrome/Firefox现代版没问题;Safari建议加
will-change: transform到全选框,减少重排开销 - 超过100个子项时,别依赖
:checked ~ input批量控制,改用JS批量setAttribute('checked', ...)更稳 - SSR场景下,服务端渲染出的初始状态若和客户端CSS状态冲突(比如服务端设了
checked但CSS还没加载),会出现闪动,需用data-ssr-checked临时标记+JS接管
事情说清了就结束。
- 正确做法:让所有待控的
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











