disabled:变体在tailwind v3+中默认不生效,需在tailwind.config.js中显式启用或引入@tailwindcss/forms插件,并重启开发服务器;推荐改用is-disabled类统一控制视觉、交互与语义。

disabled: 类名在 Tailwind v3+ 中默认不生效,不是你写错了,是它根本没被编译进 CSS。
为什么 disabled:grayscale 或 disabled:opacity-50 什么反应都没有
Tailwind v3+ 默认禁用所有 disabled: 变体,tailwind.config.js 不显式启用,JIT 就不会生成任何 button:disabled 相关规则。DevTools 里搜不到对应样式,不是热更新延迟,是压根没生成。
- 检查
plugins数组是否包含require('@tailwindcss/forms')(推荐) - 或手动注册:
plugin(({ addVariant }) => { addVariant('disabled', '&:disabled') }) - 改完必须重启开发服务器(
pnpm dev或npm run dev),HMR 不会重载变体配置 - 仅对原生可禁用元素生效:
<button></button>、<input>、<select></select>;<div disabled> 或自定义组件如 <code><mybutton disabled></mybutton>不匹配即使启用了
disabled:,也别只靠它控制禁用态iOS Safari(尤其 12–14)对
:disabled渲染极不可靠:可能跳过filter、忽略background-color更新、甚至仍响应touchstart。单写disabled:opacity-50在移动端大概率失效。- 必须组合四层控制:视觉(
opacity+color+background-color)、交互(cursor: not-allowed)、焦点(tabindex="-1"或保留但加focus:outline-none)、语义(真实disabled属性) - 避免单独依赖
filter: grayscale():高对比度模式下被系统强制禁用,旧版 iOS 渲染为全黑 - 不要用
pointer-events: none:它会让 Tab 键跳过该元素,破坏键盘导航 - SSR 场景下,服务端未渲染
disabled属性会导致首屏样式不一致——必须确保 hydration 前 DOM 已带属性
真正能落地的统一禁用方案:用
is-disabled类替代disabled:放弃让 Tailwind 动态响应
disabled属性,改用显式类名控制三层:视觉、交互、语义。这样兼容性好、可预测、易调试。- HTML 写法:
<button class="btn is-disabled">提交</button>(或保留disabled属性:<button disabled class="btn is-disabled"></button>) - CSS 定义(放在
@layer utilities或全局 CSS):.is-disabled { opacity: 0.45; color: #666 !important; background-color: #f5f5f5 !important; cursor: not-allowed; } - JS 控制:
el.classList.toggle('is-disabled', isLoading),而非el.disabled = true - 若需表单语义(如防重复提交),保留
disabled属性并叠加is-disabled,确保屏幕阅读器和浏览器行为同步
最易被忽略的点:禁用样式不是“看起来灰”,而是要同时满足 WCAG 对比度、键盘可访问、触摸反馈和语义正确——
is-disabled类比disabled:更可控,也更容易做 A/B 测试或灰度发布。 - 必须组合四层控制:视觉(











