:checked本身不渲染样式,仅作状态开关;真正生效的是通过:checked联动label或其::before/::after伪元素绘图,因checkbox/radio是替换元素,无盒模型,直接设置background、border等无效。

:checked 本身不渲染任何样式,它只是个状态开关;真正起作用的是用它联动 label 或伪元素来画图——直接给 input[type="checkbox"] 写 background 或 border 基本无效。
为什么直接改 input 样式没反应
浏览器把 input[type="checkbox"] 和 input[type="radio"] 当作“替换元素”,默认没有可渲染的盒模型,::before/::after 无法挂载,width/height 也不生效。你看到的“没变化”,不是代码写错,是浏览器根本没给你操作入口。
- 写
input:checked { background: red; }→ 完全不生效 - 只加
appearance: none→ Safari 里照样被忽略,得补-webkit-appearance: none - 加了
appearance: none但没设width/height→ 控件视觉消失,点击区域也塌缩成点,用户点不到 - 用
opacity: 0隐藏 → 可访问性尚可,但部分屏幕阅读器会误判为不可交互;更稳妥是position: absolute; clip: rect(0 0 0 0);
必须保证的 HTML 结构和关联方式
结构错一丁点,:checked + label 就断链,整个自定义逻辑失效。
-
input和label必须同级、紧邻,中间不能插空格、换行、注释或其它标签 - 要么用
,要么用嵌套写法 -
for属性值必须和input[id]**完全一致**(大小写、连字符、下划线都算) - 单选框组要互斥:所有
input[type="radio"]必须有相同的name值,例如name="theme"
用伪元素在 label 上画图的关键写法
视觉层必须落到 label 或其伪元素上,::before 画外框,::after 画勾/点,两者需协同控制。
- 未选中态:
input[type="checkbox"] + label::before设边框、圆角、尺寸 - 选中态:
input[type="checkbox"]:checked + label::after控制对勾颜色、大小、旋转角度(比如用border+transform: rotate(-45deg)拼勾) - 单选框用
border-radius: 50%+::after画实心圆点,别漏掉input[type="radio"] + label::before的圆形外框 - 想换图标?
content支持 Unicode(如"\2713")、SVG data URL 或背景图,但注意 SVG 要 base64 编码或内联才保兼容
容易被忽略的兼容性和体验细节
很多实现在线上崩,不是逻辑错,而是这些点没兜住。
-
label必须有足够点击热区(比如加padding),否则移动端点不准 - 焦点态(
:focus-within或input:focus + label)要加 outline 或阴影,否则键盘用户找不到当前控件 -
:disabled状态下:checked仍匹配,得显式写input:disabled:checked + label::after来降级样式 - 暗色模式下,别只靠
prefers-color-scheme切背景色,accent-color在 Safari 15.4+ 才稳定,别当主力方案
最常翻车的地方是结构松散和伪元素层级错位——检查时先打开 DevTools,点一下复选框,看 :checked 是否真匹配上了,再往上查父容器是否干净、label 是否被意外包裹或打断。一旦结构稳了,样式就是填空题。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











