只有原生可禁用元素(如button、input等)才响应:disabled伪类;非原生元素需改用class或语义化重构,并同步处理dom属性、css样式与js行为。

button、input等原生表单元素才能用 :disabled
只有 button、input(除 type="hidden")、select、textarea、fieldset、optgroup、option 这些浏览器规范认定的可禁用元素,才真正响应 :disabled 伪类。写 div:disabled 或给自定义组件加 disabled 属性,CSS 完全不匹配——不是写法错,是语义不被识别。
常见错误现象:
- Vue/React 组件里写了
:disabled="true",但最终 DOM 的<button></button>上没出现disabled属性 →:disabled规则不触发 - 用了
fieldset disabled,但只写了input:disabled→ 子input实际没带disabled属性,得改用fieldset:disabled input -
div disabled="true"看似像禁用,但 JS 事件照常触发,屏幕阅读器也读作“可用”
:disabled 样式必须显式重置多个属性
仅靠 opacity: 0.6 或 filter: grayscale(1) 是危险的:它不改光标、不阻止焦点、在高对比度模式下可能不可读,Safari 旧版还可能把灰度渲染成全黑。
可靠写法要同步控制:
-
cursor: not-allowed(否则鼠标还是手型,用户会误点) -
color和background-color显式设为低饱和度值(如color: #999、background-color: #f5f5f5) -
border-color或outline降级(避免禁用后边框反而更醒目) -
input:disabled:focus { outline: none; }消除键盘聚焦干扰
示例:
button:disabled,<br>input:disabled,<br>select:disabled,<br>textarea:disabled {<br> opacity: 0.6;<br> color: #999;<br> background-color: #f5f5f5;<br> border-color: #ccc;<br> cursor: not-allowed;<br>}
非原生元素(如 div、自定义组件)必须换思路
如果必须用 div 或封装过的 <mybutton></mybutton>,:disabled 就是死路一条。正确路径只有两条:
- 优先重构为语义化原生元素:把
<div onclick> 改成 <code><button type="button"></button>,这是成本最低、无障碍最稳的解法 - 放弃
:disabled,改用 class 控制:<mybutton class="is-disabled"></mybutton>,再写.is-disabled { cursor: not-allowed; opacity: 0.6; } - 若用 class,务必同步处理行为层:JS 事件 handler 开头加
if (el.classList.contains('is-disabled')) return;,并设置aria-disabled="true" - 用
el.setAttribute('disabled', 'true')能让样式生效,但语义弱;推荐直接操作 IDL 属性:el.disabled = true - React 中别写
disabled={isLoading ? true : false},应写disabled={isLoading},否则false值不会移除属性,DOM 上残留disabled="",按钮真被禁用 - Vue 中确保
v-bind:disabled="isDisabled"透传到了底层<button></button>,而不是只挂在 wrapper 元素上 - 测试时直接在 DevTools 里删掉 DOM 的
disabled属性,看样式是否立刻回退——这是验证:disabled是否真起作用的最快方式
动态禁用时 JS 写法直接影响样式生效
DOM 层和 JS 层的 disabled 状态必须一致,否则样式不会更新。常见坑点:











