单选按钮需用label包裹并借助伪元素实现图标:将input设为absolute隐藏,通过label::before绘制自定义图标,确保结构为input+label相邻以支持:checked + label选择器,同时兼顾无障碍与主题色适配。

单选按钮本身不能直接插入图标,得靠
HTML的<input type="radio">是替换元素,不支持子内容,所以不能把<i>或<svg>直接塞进标签里。真正可行的做法是:用<label>包裹<input>,再通过::before或::after在label上绘制图标——图标实际属于label,视觉上“贴”在单选框旁边。
常见错误是写成这样:<input type="radio"><i class="icon-check"></i>,这会导致图标无法响应点击、无法同步选中状态、无障碍支持差。
- 必须为每个
input设置唯一id,对应label的for属性,否则点击图标不会触发选择 - 把
input设为position: absolute; opacity: 0;隐藏但保留可访问性,避免用display: none(会移出可访问树) - 图标尺寸、颜色、间距全部由
label::before控制,不要依赖字体图标自带的行高或默认对齐
用CSS ::before画自定义圆点+外圈,比font-icon更可控
很多教程直接用font-awesome的<i>标签加在label里,看似简单,但图标大小难对齐、颜色继承混乱、SVG内联时还得处理viewBox缩放。更稳的方式是彻底放弃字体图标,纯CSS绘制:
label::before {
content: "";
display: inline-block;
width: 18px;
height: 18px;
border: 2px solid #999;
border-radius: 50%;
margin-right: 8px;
vertical-align: middle;
}
input:checked + label::before {
background: #007bff;
border-color: #007bff;
}
注意这里用了input:checked + label组合选择器,所以HTML结构必须是<input>紧邻<label>(且label在后),不能用for关联的分离写法——否则+无法匹配。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
- 如果必须用
for关联(比如表单生成器限制),就得改用JS监听change事件,动态给对应label加class,再用.checked label::before控制样式 -
vertical-align: middle是关键,否则图标常和文字基线错位;若文字行高大,需配合line-height微调 - 想加动画?给
background和border-color加transition: all 0.2s就行,别动content(它不支持过渡)
用SVG作为background-image嵌入,兼顾清晰度和主题色
需要高清、可缩放、支持主题色切换(比如暗色模式)时,background-image: url("data:image/svg+xml,...")是更优解。SVG可内联编码,避免额外请求,还能用currentColor自动继承文字颜色。
例如未选中状态的SVG data URL(已URL编码):url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5' fill='none' stroke='%23999' stroke-width='2'/%3E%3C/svg%3E")
- 用在线工具(如https://svgomg.net)压缩SVG后再编码,不然base64太长,影响可读性
- 选中状态的SVG把
stroke换成fill,并用currentColor替代固定色值,方便CSS变量统一控制 - IE11不支持data URL作为background,如需兼容,得回退到外部SVG文件或字体图标
无障碍和键盘操作不能只靠视觉效果
加了图标后,屏幕阅读器仍需正确播报选项含义。很多人只改了样式,忘了aria-label或<label>文本内容,导致NVDA/JAWS读成“未选中 单选按钮”,完全没上下文。
- 确保每个
label内有清晰文本,比如<label><span class="icon"></span>白天模式</label>,而不是空label只靠图标传达语义 - 用
tabindex="0"和role="radio"手动增强时风险极高——原生input[type=radio]自带完整键盘逻辑(空格选中、方向键切换),强行覆盖反而破坏体验 - 测试方式很简单:拔掉鼠标,仅用Tab切换,用空格选中,看焦点是否落在正确元素、语音是否读出完整描述
最易被忽略的是focus样式——很多人只写了:checked状态,却没配:focus-visible,导致键盘用户根本看不出当前聚焦在哪一个选项上。


















