user-select: none 必须作用于直接包裹文本的元素而非外层容器,且需配合 -webkit-touch-callout: none 修复 ios 长按菜单,并排除表单、代码块及无障碍内容。

user-select: none 必须写在文本直接父容器上
很多人把 .protected 类加在 wrapper 或 section 上,但里面 p、span 仍能被选中——因为 user-select 不会自动继承,只对**自身元素及其子文本节点生效**。真正起作用的是包裹文字的最内层块级或行内元素。
常见错误现象:加了样式后双击标题还能高亮、移动端长按仍弹菜单。
- 正确做法:给
p、div、h2这类实际含文本的标签加类,而不是只加在.article这种外层容器上 - 若用 CSS-in-JS 或框架动态渲染,确保 class 确实绑定到了文本容器 DOM 节点,不是空 div 或 Fragment
- React 中若用
dangerouslySetInnerHTML,需额外给生成的div加样式,不能只作用于父组件
移动端必须补全 -webkit-touch-callout: none
iOS Safari 对 user-select: none 支持不稳定,尤其长按时仍会弹出“复制/搜索”气泡菜单——这是独立于文本选择的另一套机制,-webkit-touch-callout: none 才是关掉它的钥匙。
这个属性只对 iOS 生效,Android Chrome 忽略它,所以不影响其他平台。
- 必须和
user-select配套使用,单独加没用 - 加了之后长按无任何反馈(光标不闪、菜单不弹),体验变“哑”,建议只用于纯展示文案(如价格标签、状态 badge)
- 别加在
input、textarea上——浏览器会直接忽略,且破坏输入逻辑
表单与代码块必须显式放行 user-select: text
全局或大范围加 user-select: none 后,input、textarea、code、pre 会同步失效,用户无法输入、也无法复制示例代码。
这不是 bug,是样式层叠的必然结果。
- 必须重置:给
input、textarea、code、pre单独设user-select: text -
contenteditable="true"元素同理,需手动恢复 - 图片的
alt文本在 iOS 长按时仍可被选中,要么设alt="",要么改用背景图承载文案
无障碍访问不能被 CSS 一刀切
屏幕阅读器(如 VoiceOver)依赖文本可选性来定位、朗读内容。整段加 user-select: none 会导致视障用户完全无法获取信息,违反 WCAG 基本原则。
真正要保护的,往往只是订单号、密钥、水印文案这类非语义核心内容。
- 别给
body或整个#main加该样式 - 关键操作指引、错误提示、按钮文案,务必保持可选
- 若内容确实敏感,应评估是否该用服务端渲染 + 权限控制 + 水印替代前端“防复制”这种表面手段
user-select: none 就自动退让。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











