:disabled伪类仅匹配已添加disabled属性的原生表单控件(如<button>、<input>、<select>、<textarea>),它不触发禁用,只选中已禁用状态;必须配合HTML中disabled属性或JS中el.disabled = true使用,且需同步设置cursor: not-allowed等视觉反馈,而pointer-events: none仅屏蔽鼠标事件,不阻止键盘操作或表单提交。

用 :disabled 选中并禁用原生表单控件
只有 <button>、<input>、<select>、<textarea> 这类原生支持 disabled 属性的元素,才能被 :disabled 伪类正确匹配。它不是“让元素变禁用”,而是“选中已禁用的元素”——所以你必须先在 HTML 中写 disabled 属性(或用 JS 设置 el.disabled = true),CSS 才会生效。
常见错误是只加 class 或只改样式,结果按钮仍能点、能聚焦、表单提交时值还在。正确做法:
- HTML 中显式写
<button disabled>提交</button>,不要用disabled="false"这类无效写法 - CSS 中必须显式重置视觉反馈:
color、background-color、cursor: not-allowed,不能只依赖浏览器默认灰度 - 优先用
filter: grayscale(100%)而非单纯调低opacity,后者会降低文字可读性 - 高对比度模式下
filter会被覆盖,需补@media (forced-colors: active)兜底
pointer-events: none 不是禁用,是跳过鼠标事件
它会让元素对所有指针事件(click、hover、contextmenu、drag)完全透明,但键盘操作(Tab、Enter、Space)照常触发,屏幕阅读器仍把它当可操作项播报。所以它不适合替代 disabled,只适合临时屏蔽。
典型适用场景:
立即学习“前端免费学习笔记(深入)”;
- 加载遮罩层(需透传点击到底层内容)
- 水印、装饰性图标(无业务逻辑,纯视觉)
- 防止误触弹窗背景(但要保留滚动)
关键限制:
- 对
<input>、<button>加了它,Tab 键仍能聚焦,用户可能卡住 - 子元素设
pointer-events: auto理论上可恢复,但在旧版 Safari 和部分安卓 WebView 中不可靠 - IE10 及更早版本完全不支持
- 它不影响表单提交行为——该按钮的 value 依然会被序列化发送
别用 user-select: none 混淆“禁用交互”概念
这个属性只控制文本是否可被鼠标选中或长按复制,和点击、聚焦、提交等交互完全无关。加了它,按钮照样能点、输入框照样能输、表单照样能提交。
但它有硬性使用条件:
- 必须作用于**直接包裹文本的元素**(比如
<p>、<span>),加在外层容器上无效 - iOS 长按菜单需额外加
-webkit-touch-callout: none才能关闭 - 务必排除
<input>、<textarea>、<code>、<pre>,否则用户无法输入或复制代码 - 视障用户依赖文本可选性定位内容,整段加会违反 WCAG,慎用于核心文案
真正禁用交互,得从语义和状态一起动
仅靠 CSS 无法完成“禁用”这件事。它只是表现层,而禁用本质是状态同步:DOM 属性、JS 逻辑、表单行为、无障碍树都要一致。
所以最稳妥路径是:
- HTML 层:用原生
disabled属性(不是 class,不是 style) - CSS 层:用
:disabled写样式,同时补cursor: not-allowed和filter或opacity - JS 层:动态设置时用
el.disabled = true,别只改 class 或 setAttribute - 无障碍层:确保没手动加
tabindex或漏掉aria-disabled(非表单元素才需要)
最容易被忽略的是:表单提交时,仅靠 pointer-events: none 的按钮仍会把 value 发出去;键盘用户 Tab 到一个只加了该样式的 <button> 上,按空格照样触发 click —— 因为浏览器根本不认它“禁用了”。


















