button:disabled 加 filter 没变灰,因该伪类仅匹配原生可禁用表单元素且需真实 disabled 属性;自定义组件或 div 封装不生效,iOS Safari 对 disabled 元素的 filter 渲染也不稳定。

button:disabled 为什么加了 filter 却没变灰
因为 iOS Safari(尤其是 12–14 版)对 稳妥写法是同时声明: 真正起效的前提是:元素能接收鼠标悬停事件,且没有其他 所以必须三层同步: React/Vue 中常写 更可控的做法是用 class 控制视觉: 对应 CSS: 注意: 最易被忽略的一点:禁用态必须通过 WCAG 对比度校验——小字号文字禁用时仍需 ≥ 4.5:1,不能只凭“看起来灰一点”就认为合格。:disabled 只匹配原生可禁用的表单元素(、、),且必须真实存在 disabled 属性——不是 disabled="false",也不是自定义属性 data-disabled="true"。如果你用的是 ),button:disabled 根本不会命中。filter 在 :disabled 元素上的渲染支持不稳定:样式可能挂载成功但视觉无变化,或快速切换时闪烁。验证方法很简单:打开 DevTools,手动删掉元素上的 disabled 属性,看灰度是否同步消失——如果没变,说明压根没走这条规则。button:disabled {
filter: grayscale(100%) brightness(0.92);
color: #999;
background-color: #f5f5f5;
border-color: #ddd;
cursor: not-allowed;
transition: filter 0.15s ease, opacity 0.15s ease;
}
cursor: not-allowed 不生效的三个常见原因
cursor: not-allowed 是纯视觉提示,不拦截任何交互;但它本身容易被覆盖或失效:
pointer-events: none 会彻底阻止鼠标事件到达该元素,光标自然不会触发——此时加 cursor 没意义cursor 声明(比如 body { cursor: default; }),会继承覆盖子元素style="cursor: pointer" 直接覆盖了 CSS 规则,需加 !important 或改用更具体的选择器(如 button:disabled)cursor 声明干扰。移动端无需关注此项,它只影响桌面端反馈。禁用状态不能只靠 filter 或 opacity
filter: grayscale() 和 opacity 都只改外观,不改语义也不拦行为:
Tab 到该按钮,屏幕阅读器仍播报“提交”,回车键照样触发 click 事件opacity: 0.5 会让边框、图标、阴影一并变淡,破坏可读性,还可能让辅助技术误判内容可用性@media (forced-colors: active))下,filter 会被系统强制忽略,按钮看起来和启用态一样
disabled 属性(表单控件)或 aria-disabled="true"(非表单元素)button:disabled 或自定义 class(如 .btn--disabled),显式设 color、background-color、cursor
if (el.disabled) return;,或监听前检查状态框架里动态禁用按钮的样式陷阱
或 ,但样式更新可能滞后于 DOM 属性变更,尤其在异步操作后立即启停时。<button :disabled="isSubmitting" :class="{ 'btn--disabled': isSubmitting }">提交</button>
.btn--disabled {
color: #999;
background-color: #f5f5f5;
cursor: not-allowed;
pointer-events: none; /* 纯触摸场景可加,但会禁用焦点 */
}
pointer-events: none 会同时禁用 focus 和键盘导航,若需保留 Tab 导航能力,应避免使用,改用 disabled + JS 拦截。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











