appearance: none 必须配合前缀、尺寸重置和伪元素处理才能生效,否则 Safari 箭头残留、Chrome 点击失效、Firefox 叠加渲染;需三前缀齐写、补宽高、自定义箭头或视觉层,并统一 box-sizing、border、padding 和 focus-visible 降级。
直接用 appearance: none 不行,必须配齐前缀、尺寸和重置项,否则 Safari 里箭头还在、Chrome 里点击区域消失、Firefox 里伪元素叠着原生控件。
只写 appearance: none 就想清掉原生样式,基本等于没写。Safari 15.4 之前根本不认这个标准属性,Firefox 84 及更早版本不加 -moz-appearance: none 会把伪元素和系统圆点一起画出来,结果是“看起来没变”,其实是两层叠加。
-webkit-appearance: none 必须显式写,Safari 和旧版 Chrome 离不开它-moz-appearance: none 对 Firefox 84 及更早版本是刚需,不是可选!important 验证一下width 和 height 必须立刻补上(比如 18px),否则用户点不到appearance: none 后 select 变成裸容器,但箭头不会自动消失——浏览器会在右侧留白或渲染残影。得自己画一个,而且不能依赖 ::after 在 select 上:它的伪元素支持极差,尤其 Safari。
background-image + base64 SVG,比如:background-image: url("data:image/svg+xml;charset=US-ASCII,...")
background-position: right 0.75rem center 控制箭头位置,background-repeat: no-repeat
select 包在 <div class="select-wrapper"> 里,给 wrapper 画边框和背景,select 设 background: transparent,靠 z-index 让它浮在上面padding-right,给自定义箭头留出空间,否则文字被遮挡直接给 input[type="checkbox"] 写 background、border 基本无效,因为它是替换元素,浏览器锁死了渲染盒。你写的样式不是“没生效”,而是压根没地方画。
appearance: none + -webkit-appearance: none + -moz-appearance: none,三者缺一不可width: 18px、height: 18px,不然控件不可点label 或相邻兄弟元素承载视觉层:input:checked + label::before 是最稳的写法;若结构松散(如 Vue 动态插入),改用 input:checked ~ label::before,但中间不能插非 label 元素opacity: 0,会破坏屏幕阅读器识别;推荐 position: absolute; clip: rect(0 0 0 0)
很多人写了 appearance 就以为完事了,结果在不同浏览器里还是走样。真正统一,还得补全这三处。
box-sizing: border-box 必须显式加,尤其对 input[type="range"] 和自定义 checkbox,否则 padding 计算错位border、background、padding 不能省——不同浏览器默认值差异极大,比如 Safari 给 select 的 padding 比 Chrome 多 2px:focus-visible 要配合键盘操作测试,仅靠 :focus 会漏掉键盘用户的焦点指示,且部分浏览器(如旧版 Safari)不支持 :focus-visible,得降级 fallback最麻烦的不是写多少 CSS,而是每种控件都要单独验证:Safari 的 select 箭头、Firefox 的 radio 尺寸、Windows Edge 的 input[type="number"] 增减按钮——它们各自咬住一个角落不放,得一个个掰开看。