应避免使用 :not(:checked),因其在旧版 Safari、Android WebView 和 IE 中不被支持或行为不稳定;可靠写法是直接定义 input[type="checkbox"] 样式,再用 :checked 覆盖已选中状态。

直接用 :not(:checked) 会失效
很多开发者一上来就写 input[type="checkbox"]:not(:checked) { ... },发现样式完全不生效。这不是浏览器 bug,而是 CSS 选择器的限制:伪类 :not() 里只能放「简单选择器」,而 :checked 是一个**用户动作相关的动态伪类**,在部分浏览器(尤其是旧版 Safari 和某些 Android WebView)中,:not(:checked) 不被支持或行为不稳定。
真正可靠的未选中状态写法是「不加任何伪类」
复选框默认就是未选中状态,所以最稳妥的方式是直接针对元素本身写样式,再用 :checked 覆盖已选中的情况:
input[type="checkbox"] {
/* 这里定义未选中时的外观:比如边框、背景、尺寸 */
width: 18px;
height: 18px;
accent-color: #999;
}
input[type="checkbox"]:checked {
/ 仅覆盖已选中时的变化,比如颜色、图标等 /
accent-color: #007bff;
}
-
accent-color是现代浏览器中控制复选框主色调的标准属性,比 hack 背景图更干净 - 不要试图用
:not(:checked)去隐藏原生控件再自定义 —— 那会破坏可访问性(screen reader 无法识别) - 如果必须做深度定制(如换图标),应包裹
,用input:checked + label::before控制视觉层,原生input保持隐藏但保留语义
兼容老浏览器时避免 :not(:checked)
IE 完全不支持 :not() 嵌套伪类;iOS 13.3 之前 Safari 对 :not(:checked) 渲染有延迟;部分微信内置 WebView 会忽略该选择器。实测有效 fallback 方案:
- 用 class 控制状态:
,JS 监听change事件切换.is-checked类 - 样式上写两组规则:
.custom-checkbox(未选中)和.custom-checkbox.is-checked(选中) - 这样逻辑清晰、调试方便、兼容性拉满,且不影响表单提交值
注意「未选中」不等于「未交互」
刚加载页面时复选框是未选中,但用户点击后取消也会回到未选中——这两个状态在 DOM 上完全一样,CSS 无法区分。如果你需要样式表达「从未点过」和「点过又取消」的区别,纯 CSS 做不到,必须靠 JS 记录 click 或 input 事件次数,然后打不同 class。
立即学习“前端免费学习笔记(深入)”;
也就是说,CSS 的「未选中」只是值层面的 checked === false,它不携带任何操作历史信息。










