:disabled伪类仅对原生表单控件生效,自定义组件需同时用[disabled]和[aria-disabled="true"]覆盖;禁用态禁用opacity而应分层调整颜色与背景,并确保状态规则与hover同级且顺序在后。

禁用态样式异常,基本是因为 mixin 没同时覆盖原生 [disabled] 和语义化 [aria-disabled="true"] 两种状态判定方式,或用了 opacity: 0.5 这类破坏可访问性的写法。
为什么 :disabled 选择器在自定义组件里完全不生效
原生 HTML 元素(如 <button disabled></button>、<input disabled>)才响应 :disabled 伪类;而 React/Vue 封装的 <custombutton aria-disabled="true"></custombutton> 是普通元素,:disabled 对它无效。
常见错误写法:&:disabled { opacity: 0.5; } → 编译后是 .btn:disabled,只匹配原生按钮,自定义组件样式丢失。
正确做法必须双路覆盖:
-
&[disabled], &[aria-disabled="true"] { ... }—— 同时命中原生属性和 ARIA 属性 - 禁止只写
:disabled或只写[aria-disabled],否则必漏一端 - 若组件封装了
disabledprop 并透传到根元素,确保最终渲染出的是disabled属性(原生)或aria-disabled(非原生)
为什么禁用态用 opacity: 0.5 会导致文字颜色不可读
Opacity 会把整个元素(包括子元素)透明度统一降低,导致文字色与背景对比度跌破 WCAG 4.5:1 的可访问性底线,尤其在暗色主题下更明显。
Less 中应避免硬写 opacity,改用颜色函数动态调整:
-
background-color: desaturate(@bg, 50%);—— 降低背景饱和度,保留明度层次 -
color: fadeout(@text, 30%);—— 仅淡出文字色,不碰背景 - 禁用态不能依赖
contrast(@bg)自动推导文字色 —— 它在深色背景下常返回白色,但禁用态本就不该高亮
为什么调用 .button-state(disabled) 后 hover 样式还在生效
这说明禁用态 mixin 没做优先级压制,或者 hover 规则被写在了更外层选择器里,导致禁用态无法覆盖。
关键约束:
- 禁用态规则必须和 hover 写在同一级选择器下,例如:
.button { &:hover { ... } &[disabled], &[aria-disabled="true"] { ... } } - 不要把
.button-state()拆成独立文件后单独@import到不同位置 —— Less 不保证规则顺序,CSS 层叠靠源码顺序 - 如果用了
!important强制覆盖,说明结构已失控;正解是让禁用态规则生成在 hover 之后,且选择器权重一致
真正麻烦的不是写错一行,而是禁用态逻辑分散在尺寸、颜色、状态三个 mixin 里,改一处要同步五处。别让 .button-state() 只管“是否禁用”,它得管“禁用时背景怎么降、文字怎么淡、光标怎么变、焦点怎么移除”。漏掉任意一环,用户点下去就感觉“卡住但没反馈”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











