:checked 伪类仅在 radio/checkbox 的 checked 属性为 true 时匹配,需配合 +/~ 选择器控制关联标签样式,并隐藏原生 input;常见失效原因包括缺 name、for/id 不匹配、漏 cursor:pointer 等。

如何用 :checked 捕获单选框真实选中状态
:checked 只对 <input type="radio"> 和 <input type="checkbox"> 生效,且仅当元素被用户主动勾选(或通过 js 设置 checked 属性)时才匹配。它不响应 disabled 状态下的选中,也不管表单是否提交——只看 dom 中的 checked 属性是否存在。
注意:不能直接给 <input> 加样式(浏览器默认控件不可样式化),必须借助相邻/子元素配合 + 或 ~ 选择器“外溢”控制。
自定义单选框外观的最小可行结构
必须把 <input> 和用于展示的标签(如 <label></label> 或 <span></span>)放在同一父容器内,且 <input> 在前:
<div class="radio-group"> <input type="radio" name="theme" id="theme-dark" value="dark"> <label for="theme-dark">深色模式</label> </div>
然后用 input[type="radio"]:checked + label 控制对应 label 的样式。如果中间有其他元素,+ 就失效,得改用 ~(通用兄弟选择器)。
立即学习“前端免费学习笔记(深入)”;
-
+要求目标元素紧邻在后,性能略好,推荐优先使用 -
~匹配之后所有同级元素,更灵活但选择范围宽,可能误中 - 别忘了加
display: none隐藏原生<input>,否则会双显
:checked 与伪元素结合画自定义圆点
真正做 ui 替换时,通常用 label::before 或 label::after 画一个圆圈,再通过 :checked + label::before 改变它的背景、边框或 transform。
常见写法示例:
input[type="radio"] { display: none; } label::before { content: ""; display: inline-block; width: 18px; height: 18px; border: 2px solid #999; border-radius: 50%; margin-right: 8px; } input[type="radio"]:checked + label::before { background: #007bff; border-color: #007bff; } input[type="radio"]:checked + label::after { content: "•"; color: white; font-size: 12px; position: relative; top: -2px; left: -6px; }
注意:::after 里用字符打点只是快速示意,生产环境建议用 background 或 SVG;top/left 偏移依赖字体渲染,不如用 transform: translate() 稳定。
为什么点击没反应?几个高频漏点
自定义单选框失效,90% 出现在这几个地方:
-
<input>缺少name属性 → 浏览器不认为它们是一组,无法互斥 -
for属性值和id不一致,或<input>没写id→ 点击label不触发选中 - css 中漏了
cursor: pointer在label上 → 用户感知不到可点击 - 用了
pointer-events: none在父容器或input上 → 阻断了事件冒泡 - JS 动态插入的 radio 没绑定事件,或未用
setAttribute('checked', '')而是只改了.checked = true→ 后者不会触发:checked伪类重绘(部分旧浏览器)
最稳妥的调试方式:打开 DevTools,手动在 Elements 面板勾选 checked 属性,看样式是否立刻生效——如果生效,说明结构和 CSS 没问题,问题出在交互链路上。