单选按钮不能直接用 appearance: none,因旧版 safari 和 android webview 中不生效,且会导致焦点丢失、可访问性失效;必须保留原生 input 元素,用 position: absolute + opacity: 0 隐藏,并通过 label 关联实现语义与交互完整。

单选按钮默认样式为什么不能直接用 appearance: none?
浏览器对 <input type="radio"> 的原生渲染控制极强,appearance: none 在部分旧版 Safari 和某些 Android WebView 中不生效,或导致焦点状态丢失、可访问性(a11y)失效。更关键的是:即使隐藏了原生控件,若不手动处理 :checked 状态和键盘导航(如空格键切换),屏幕阅读器可能完全忽略该控件。
- 必须保留原生
<input>元素,不可替换成<div> 或 <code><span></span>模拟 - 隐藏原生控件推荐用
position: absolute; opacity: 0; width: 1px; height: 1px;组合,比display: none或visibility: hidden更安全(前者移除可访问性,后者仍占布局空间) - 所有视觉样式必须绑定到其后的
<label></label>或相邻兄弟选择器(如input + label)
怎么用伪元素画一个圆环+实心圆的自定义单选?
核心是利用 input:checked + label::before 和 input:checked + label::after 分层绘制外圈与内点。注意伪元素默认无法响应点击,所以必须确保 <label></label> 包裹 <input> 或设置 for 属性关联。
input[type="radio"] {
position: absolute;
opacity: 0;
width: 1px;
height: 1px;
}
<p>input[type="radio"] + label {
position: relative;
padding-left: 28px;
cursor: pointer;
}</p><p>input[type="radio"] + label::before {
content: "";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 16px;
height: 16px;
border: 2px solid #999;
border-radius: 50%;
}</p><p>input[type="radio"]:checked + label::after {
content: "";
position: absolute;
left: 6px;
top: 50%;
transform: translateY(-50%);
width: 4px;
height: 4px;
background: #007bff;
border-radius: 50%;
}</p>
- 外圈用
::before绘制,内点用::after,避免使用 box-shadow 模拟内点(缩放时易糊) -
transform: translateY(-50%)比top: Xpx更可靠,适配不同行高 - 不要给伪元素设
pointer-events: none—— 它不影响点击穿透,但可能干扰 focus outline 渲染
移动端点击区域太小,如何安全扩大又不破坏语义?
原生单选按钮点击热区通常只有 12–16px,用户拇指极易点偏。扩大方式必须保持语义完整和键盘可操作性:
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
- 用
label的padding-left扩展可点击区域,而非放大伪元素本身 - 确保
label的min-height≥ 44px(iOS 最小触控建议值),并设置line-height与之匹配 - 若用
<label for="id"></label>结构,for值必须严格对应input的id,大小写和空格都不能错 - 避免给
label设display: block后又加margin—— 这会导致相邻选项间距不可控,改用gap或flex-direction: column布局更稳
聚焦态(focus)和禁用态(disabled)容易被忽略的细节
很多自定义样式只处理 :checked,却漏掉 :focus-visible 和 :disabled,造成键盘用户无法感知当前焦点,或禁用项视觉无反馈:
-
input:focus-visible + label::before应添加清晰的焦点轮廓(如outline: 2px solid #007bff; outline-offset: 2px;),不要仅靠颜色变化 -
input:disabled + label要同时降低文字色(color: #999)和伪元素边框色(border-color: #ccc),且禁用cursor: not-allowed - Safari 对
:focus-visible支持较晚,必要时回退到:focus,但需配合focus-ring检测逻辑避免鼠标点击也出 outline(可查prefers-reduced-motion或用 JS 判断)
真正难的不是画个好看的圆,而是让这个圆在 NVDA、VoiceOver、键盘 Tab、高对比度模式、缩放 200% 下都正常工作。样式可以炫,但语义链和交互反馈断不得。










