user-select 是控制文本选中的最直接轻量手段,但仅作用于用户交互层,无法防止查看源码、DevTools 抓取或替代服务端权限控制;真防复制需组合策略,单靠 CSS 或 JS 均无效。

user-select 是控制文本能否被选中的最直接、最轻量的手段,但它仅影响用户交互层,**不能防止查看源码、不能阻止 DevTools 抓取 DOM、也不能替代服务端权限控制**。真要防复制,得组合策略;只靠 CSS 或只靠 JS 单点拦截,基本等于摆设。
用 user-select 精确控制可选区域
全局禁用(如 body { user-select: none })会伤及表单输入、代码块、按钮文字等正常交互,反而引发可访问性问题。更合理的是按需标记:
- 给需要保护的容器加 class,例如
.protected-content,并在 CSS 中写:.protected-content { -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } - 允许其中某段文字可选(比如“联系邮箱”),就给子元素加
.allow-copy并覆盖样式:.protected-content .allow-copy { -webkit-user-select: text; -moz-user-select: text; -ms-user-select: text; user-select: text; } - 别忘了移动端:安卓 4.0+ 需
-webkit-前缀;iOS Safari 对user-select支持良好,但双击选词可能失效——此时需确保该元素有style="user-select: text",否则selectstart监听也救不回来
用 selectstart 事件做动态拦截
CSS 的 user-select 是声明式控制,而 selectstart 是命令式干预,适合条件复杂或需响应式开关的场景:
- 监听时必须用
e.preventDefault(),且要在捕获阶段或冒泡早期触发,否则部分浏览器(如旧版 Edge)可能已开始选中 - 别直接绑在
document上全拦,应判断目标:document.addEventListener('selectstart', (e) => { if (e.target.closest('.protected-content') && !e.target.closest('input, textarea, [contenteditable]')) { e.preventDefault(); } }); - 注意:Chrome 90+ 中,
contenteditable元素内触发selectstart可能被忽略,此时必须靠 CSSuser-select: text保底,否则双击失灵
右键与粘贴行为必须单独处理
禁选 ≠ 禁右键 ≠ 禁粘贴。三者独立触发,缺一不可:
立即学习“前端免费学习笔记(深入)”;
- 右键菜单由
contextmenu事件控制,同样建议条件拦截:document.addEventListener('contextmenu', (e) => { if (e.target.closest('.protected-content')) { e.preventDefault(); // 可选:showCustomContextMenu(e.clientX, e.clientY) } }); - 粘贴内容无法靠
user-select拦截,必须监听paste事件并调用e.preventDefault(),再手动取e.clipboardData.getData('text/plain')插入——否则用户 Ctrl+V 仍可绕过 - 拖放(
dragstart/drop)也要禁,否则图片、链接可直接拖进页面篡改 DOM;简单写法是ondragstart="return false",但推荐统一用 JS 绑定避免遗漏
真正容易被忽略的坑
多数人卡在「为什么加了 user-select: none 还能选中?」——常见原因不是代码没生效,而是:
- CSS 权重被更高优先级规则覆盖(比如某个
!important的user-select: text) - 目标元素是
iframe子页面,父页样式完全不生效,必须在子页内单独设置 - 用了
innerText获取内容做校验,结果因 CSSdisplay: none或重排导致值为空或错乱;一律改用textContent - 以为加了防护就高枕无忧,却忘了 DevTools 里
$0.textContent一行就能拿到全部文本——所有前端防护都只是提高普通用户门槛,不是加密



















