:disabled伪类仅匹配原生可禁用元素,不匹配自定义标签;需将disabled属性透传至内部原生button并验证其存在,推荐使用[disabled]属性选择器确保兼容性。

:disabled 伪类根本不会匹配自定义按钮——它只认原生可禁用元素,比如 <button></button>、<input>、<select></select>。你写 <my-button disabled></my-button> 或 <div disabled>,浏览器直接当普通属性处理,CSS 引擎压根不查。
<h3>为什么自定义组件里 <code>:disabled 完全没反应
浏览器实现上,:disabled 是基于 HTML 规范的语义判断,不是“看到 disabled 属性就匹配”。只有 UA 样式表注册过的那几类原生元素才被允许进入禁用状态。自定义标签哪怕带 disabled 属性,也属于无效属性,不会触发伪类匹配。
常见错误现象包括:
- React 中写了
disabled={isSubmitting}却没绑定到内部<button></button>上,最终 DOM 里<button></button>没disabled属性 - Vue 用了
v-bind:class="{ disabled }",只是加 class,没设:disabled属性 - 开发者工具里看到根节点有
disabled,但子节点<button></button>上没有——样式自然不生效
怎么让禁用样式真正起作用
必须把 disabled 属性透传到内部原生按钮上,且验证最终渲染出的 <button></button> 标签是否真实存在 disabled 属性(空值或布尔值均可,但不能是字符串 "disabled")。
实操建议:
- React:用
<button disabled></button>,检查shouldForwardProp是否过滤了disabled - Vue 2:用
<button :disabled="isDisabled" v-bind="$attrs"></button>;Vue 3 若设了inheritAttrs: false,必须手动v-bind="$$attrs" - Svelte:推荐
<button bind:disabled="{disabled}"></button>,更稳妥 - 避免写成
:disabled="isSubmitting ? 'disabled' : null"——字符串值不会被识别为真禁用
为什么更推荐用 [disabled] 而不是 :disabled
[disabled] 是属性选择器,行为确定、兼容性好,尤其适合封装场景:
- 匹配任意含
disabled属性的元素,包括<my-button disabled></my-button>、<div disabled> <li>IE8+ 支持,不受 Safari </li> <li>但注意:JS 动态设置 <code>el.disabled = true不会自动添加 HTML 属性,得配el.toggleAttribute('disabled', true)或el.setAttribute('disabled', '') - 实际项目中,建议同时写
button:disabled, button[disabled],覆盖 SSR 和 JS 动态两种场景
最易被忽略的一点:禁用状态是否真正同步到了原生按钮的 DOM 属性上,而不是仅挂在自定义组件 props 或 class 上。打开开发者工具,逐层点开,确认那个 <button></button> 标签上有没有 disabled 这个 attribute——没有,就别指望 :disabled 或 [disabled] 能生效。











