user-select: none 对 input 和 textarea 完全无效,因浏览器规范强制要求表单控件支持文本选择,css 层级被忽略;contenteditable="true" 元素同理,需改用 contenteditable="false" 或 js 拦截 selectstart/contextmenu 事件。

user-select: none 为什么对 和
浏览器规范明确要求表单控件必须支持文本选择,user-select: none 在 <input>、<textarea></textarea> 和 contenteditable="true" 元素上会被直接忽略——这不是 bug,而是强制行为。即使你给父容器写了四套前缀,子元素里的输入框照样双击可选、光标可定位。
实操建议:
- 不要试图用
user-select: none控制表单控件;若需只读展示,改用<div contenteditable="false"> + 显式声明 <code>user-select: none - 真要干预输入框选中逻辑,只能靠 JS 拦截
selectstart事件或重置selectionStart/End - 注意
pointer-events: none会同时禁用聚焦和点击,不能当替代方案 - 必须叠加
-webkit-touch-callout: none抑制菜单弹出 - 对非表单区域,可加
ontouchstart="event.preventDefault()",但要小心它会阻断滚动 - 更稳妥的是监听
selectstart+contextmenu两个事件并preventDefault() - 没写全前缀:
-webkit-user-select: none(iOS/Safari 必需)、-moz-user-select: none(Firefox ≤68)、-ms-user-select: none(旧 Edge),缺一不可 - 子元素显式设了
user-select: text,比如第三方组件内部样式,直接覆盖继承值 - 目标元素在 Shadow DOM 内部,外部样式无法穿透,必须在 shadow root 里单独声明
- 用了
* { user-select: none; }全局重置,结果<button></button>文字也变不可选,用户连点击都困惑 - 禁用选中必须作用于宿主元素,例如
.label { user-select: none; },而不是.label::before { user-select: none; } - 禁用后
::selection样式本身也失去意义,别指望靠它“防复制” - 如果只改了
::selection背景色却没关user-select,用户照样能复制——这根本不是防复制的方案
移动端长按仍弹出“复制”菜单的真正原因
iOS Safari 对长按行为有独立策略层,user-select: none 只影响拖选流程,不阻断系统级上下文菜单触发。哪怕你写了 -webkit-user-select: none,只要元素绑了 ontouchstart 或设置了 cursor: pointer,长按就可能呼出浮层。
实操建议:
为什么写了 user-select: none 还是能选中?四个常见漏点
失效往往不是语法错,而是被其他规则覆盖或作用域没对上:
::selection 和 user-select 的根本混淆点
::selection 只控制已选中文本的样式(比如背景色),它完全不参与“能不能选”的判断。很多人在 ::selection 里写 user-select: none,这行声明会被浏览器直接忽略——伪元素不支持该属性,也不响应选择逻辑。
实操建议:
真正难处理的是富文本区域或自定义编辑器,那里 user-select 单独不够用,得结合事件拦截和 selection API 才能控制住。











