:enabled只匹配原生支持disabled属性且DOM无disabled属性的表单控件,如input(hidden除外)、button、select、optgroup、textarea;不匹配div、p或自定义组件上的disabled属性,fieldset禁用下的子元素虽不可交互但仍匹配:enabled。
:enabled 只匹配真正原生支持 disabled 属性、且当前 DOM 上没有 disabled 属性的表单控件——不是“看起来能点”,而是浏览器底层认定“可聚焦、可输入、可提交”的元素。
仅限以下原生表单控件(且排除特例):
<input>(type="hidden" 除外)<button><select> 和 <optgroup>
<textarea>以下写法完全无效:
<div disabled> —— 浏览器不认,:enabled 直接跳过整条规则<my-input disabled> 或 Vue/React 中 :disabled="false" 但未渲染出 DOM 属性 —— CSS 无法感知响应式变量,只看真实 DOM<p disabled> —— p 标签原生不支持 disabled,伪类无意义这是最容易误判的场景:一个 <input> 没写 disabled,但被包裹在 <fieldset disabled> 里,它依然会匹配 :enabled —— 因为它的 DOM 上确实没 disabled 属性。
但用户实际无法操作它。这意味着:
fieldset[disabled] input 覆盖样式,或改用 JS 控制子元素的 disabled 属性常见失效路径:
contenteditable 的 div)el.disabled = true,但没触发属性同步(旧版 Safari 或某些框架中,需显式调用 el.setAttribute('disabled', ''))input:hover:enabled —— 伪类顺序错误,部分浏览器(尤其 Safari)不识别,应写成 input:enabled:hover
:disabled="loading",但 loading 初始为 undefined → 渲染时没生成 disabled 属性 → :enabled 默认命中,造成“本该禁用却显示启用样式”表面等价,但语义与兼容性不同:
:enabled 是语义化伪类,只作用于表单控件;:not(:disabled) 是通用否定逻辑,对不支持 disabled 的元素(如 p)也会匹配:not(:disabled) 对 <option> 支持不稳定,而 :enabled 稳定fieldset[disabled] 禁用时::enabled 仍匹配(DOM 无属性),:not(:disabled) 同样匹配 —— 二者在此场景下行为一致,但前者意图更清晰真正容易被忽略的是焦点残留问题:用户 tab 进入一个刚被 JS 设为 disabled 的 input,焦点还在,但 :enabled:focus 不再生效,此时仅靠 CSS 无法还原视觉反馈,必须用 JS 监听 focusin 并手动移出焦点或加 class 补偿。