使用 CSS,可以通过 user-select: none
来阻止用户选择元素内的文本。 现在,可以理解为什么这样做可能被认为是“有争议的”。 我的意思是,我们应该禁用标准的用户行为吗? 一般来说,不,我们不应该这样做。 但是禁用文本选择是否有一些合法的(尽管很少见)用例? 我认为是。
在本文中,我们将探讨这些用例,并了解如何使用 user-select: none
来改善(而不是阻碍)用户体验。 值得注意的是,user-select
属性除了 none
之外还有其他值,这些值可用于更改文本选择的行为,而不是完全禁用它,以及另一个强制执行文本选择的值,因此我们也将看看这些值。
user-select
值
可能的 让我们从遍历不同的 user-select
值及其功能开始。
将 user-select: none;
应用于元素意味着其文本内容和嵌套文本内容将无法在功能上或视觉上被选择(即 ::selection
不起作用)。 如果您要进行包含一些不可选择内容的选择,则不可选择内容将从选择中省略,因此实现相当完善。 而且支持度很高。
此浏览器支持数据来自 Caniuse,其中提供了更多详细信息。 数字表示浏览器在该版本及更高版本上支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
4* | 2* | 10* | 12* | 3.1* |
移动设备/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 2.1* | 3.2* |
相反,user-select: text
使内容可选择。 您可以使用此值覆盖 user-select: none
。
user-select: contain
很有趣。 应用它意味着如果选择从元素内部开始,那么它也必须在元素内部结束,包含它。 但是,这在选择从元素之前开始时却奇怪地不适用,这可能就是目前没有浏览器支持它的原因。(Internet Explorer 和早期版本的 Microsoft Edge 以前在 user-select: element
的掩护下支持它。)
使用 user-select: all
,选择元素内容的一部分会导致所有内容自动被选择。 这是全有或全无,非常不妥协,但在用户更有可能将内容复制到剪贴板的情况下很有用(例如,共享和嵌入链接、代码片段等)。 用户只需单击一次即可自动选择内容,而无需双击。
但要小心,因为这并不总是您认为的功能。 如果用户只想选择内容的一部分(例如,Google Fonts 代码片段中只有字体名称部分,或者代码片段中的一小部分)呢? 在许多情况下,使用 JavaScript 处理“复制到剪贴板” 仍然更好。
user-select: all
的一个更好的应用是确保完全准确地复制引号。
user-select: auto
(user-select
的初始值)的行为取决于元素及其使用方式。 您可以在 我们的年鉴 中了解更多信息。
现在让我们转到探讨 user-select: none
的用例…
从选择中删除非文本内容
当您从网页中复制内容时,它很可能来自文章或其他类型的长篇内容,对吧? 您可能不希望您的选择包含图像、表情符号(有时可以作为文本复制,例如“:thinkingface:”)以及您可能希望在 <aside>
元素中找到的其他内容(例如,文章内行动号召、广告或其他不是主要内容的一部分的内容)。
要防止某些内容包含在选择中,请确保它包含在 HTML 元素中,然后对其应用 user-select: none
<p>lorem <span style="user-select: none">🤔</span> ipsum</p>
<aside style="user-select: none">
<h1>Heading</h1>
<p>Paragraph</p>
<a>Call to action</a>
</aside>
在这种情况下,我们不是禁用选择,而是优化选择。 值得一提的是,选择并不一定意味着复制 - 许多读者(包括我自己)喜欢在阅读时选择内容,以便记住他们所在的位置(就像书签一样),这也是优化而不是完全禁用的另一个原因。
防止意外选择
将 user-select: none
应用于看起来像按钮的链接(例如 <a href="/whatever" class="button">单击我!</a>
)。
无法选择 <button>
或 <input type="submit">
的文本内容,因为,好吧,为什么要这样做呢? 但是,这种行为不适用于链接,因为传统上它们是段落的一部分,应该是可选择的。
说得通。
我们可以争论说,让链接看起来像按钮是一种反模式,但无论如何。 它不会破坏互联网,是吗? 那艘船早就出发了,所以如果您使用的是设计成像按钮一样的链接,那么它们应该模仿按钮的行为,这不仅是为了保持一致性,而且是为了防止用户意外选择内容而不是触发交互。
我当然容易意外选择东西,因为我躺在床上使用笔记本电脑的时间比我想承认的要多。 另外,有几种疾病会影响控制和协调,将原本的点击变成意外的拖动/选择,因此 user-select
也可以解决可访问性问题。
当然,也存在需要(有意)拖动的交互(例如,在浏览器游戏中),但这些并不常见。 不过,这仅仅表明 user-select
实际上确实有很多用例。
避免付费内容被盗
付费内容受到很多人的讨厌,但如果您觉得需要保护您的内容,那就是您的内容 - 没有人有权只是因为他们不认为应该为此付费而窃取它。
如果您想走这条路线,有很多方法可以使用户更难以绕过付费墙(或者类似地,复制他人的已发布作品等受版权保护的内容)。
使用 CSS 模糊内容
article { filter: blur(<radius>); }
禁用 DevTools 的键盘快捷键
document.addEventListener("keydown", function (e) {
if (e.keyCode == 123) e.preventDefault();
else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 73) e.preventDefault();
else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 74) e.preventDefault();
else if ((e.ctrlKey || e.metaKey) && e.altKey && e.keyCode == 85) e.preventDefault();
});
通过禁用上下文菜单本身来禁用从上下文菜单访问 DevTools
document.addEventListener("contextmenu", e => e.preventDefault())
当然,为了防止用户在未被允许阅读源内容的情况下复制内容,请应用 user-select: none
<article style="user-select: none">
还有其他用例吗?
这些是我能想到的三个防止文本选择的用例。 我脑海中闪过其他一些,但它们似乎都有些牵强。 但是您呢? 您是否曾经在任何地方禁用文本选择? 我想知道!
关于阻止用户“窃取”付费内容的部分实际上并不适用。 用户仍然可以打开 DevTools 并通过选择元素来复制文本; 即使要随机化并自动生成类和 div 来对内容进行混淆,也可以通过 OCR 程序覆盖它。
当然,但这只是假设用户甚至知道什么是 DevTools(大多数人不知道)。
伙计,如果您要发送付费内容,那么一点点反用户 CSS 无法保护它。 您需要完全不发送它,因为您列出的对策几乎没有用。
即使假设我不能通过浏览器的菜单打开开发者工具(我可以),curl 也存在。如果你真的需要保护你的内容,你需要真正地保密,而不是将它放在公共 URL 的源代码中。
除了普通用户不知道 DevTools/curl/等是什么。
lmao。普通用户无论如何都不会窃取你的内容。
想要窃取你内容的人知道如何获取。如果你不希望这种情况发生,就不要在公共 URL 上提供你的内容。
此外,当你切换到阅读模式时,所有的小技巧都失效了,它会剥离你所有花哨的 CSS 和 JavaScript——只需按一下按钮即可。
关于:避免付费内容被盗
Ctrl-l Ctrl-a Ctrl-c – 我有 URL
Ctrl-w Ctrl-t – 我有一个新标签,空着
Ctrl-Shift-i – 我打开了开发者工具
Ctrl-l Ctrl-v enter – 我打开了你的宝贵页面,开发者工具也已打开。
试图阻止人们获取他们正在浏览的内容注定会失败。获取内容的方法太多了。因此,这不是一个有效的用例。
感谢你提醒我快捷键(我忘记了 cmd-l)。
然而,对于大多数没有我们那么精通技术的人来说,这是一个有效的用例。
不幸的是,我见过一些网站检测到开发者工具,如果开发者工具打开,就会阻止内容加载。:(
我希望开发者工具有一种“隐形模式”,可以使它们无法被检测到。可能不是所有的功能都能使用,但它仍然非常有用。
对于可拖动元素,禁用选择可能是合适的。
是的!例如游戏。就我个人而言,我不太喜欢复杂的交互,尽管如此。
我对这个问题的看法完全不同。我想控制用户体验,用户在使用网站时看到元素上的不必要突出显示是不可取的。因此,我在 body 上设置了 user-select:none; 然后在用户可能想要复制的页面内容元素上重新添加它。我不想让他们复制侧边栏的标题。我不想因为用户拖动了一点,就让随机元素上出现高亮框。去除用户选择是我最喜欢的发现之一,我认为管理这种行为是我擅长的一部分。
我认为我同意这种方法,但我担心我会忘记为需要选择内容的元素启用选择。我想知道浏览器处理选择的方式是否完全错误,这种行为应该成为标准。
断言:禁用模糊滤镜和 JS 事件处理程序以查看我电脑上的内容,而发布者不希望这样 => 窃取。
反断言:未经我许可或同意将不可读内容放置在我的电脑上 => 入侵。
我曾经有一个很好的理由这样做。
我正在开发一个绘图应用程序,当我尝试用 iPad 绘图时,它会将绘图区域选择为可以复制的内容。
使用 user-select none 解决了这个问题。
我使用
user-select: none;
的唯一时间是用于增强用户体验。代码示例可能将行号设置为不可选择,以便可以将代码直接复制,而无需删除行号。
命令行示例可能将提示字符串设置为不可选择,以便更轻松地复制用户可能想要运行的命令。
为了视觉效果而复制的部分内容可能包含一个不可选择的副本,这样复制它就不会包含重复内容。
人们可能会争论不可选择的
<aside>
元素的好处,因为它们可能会干扰对主文本的选择,但<aside>
的内容通常出现在那里,因为它们包含用户可能想要复制的宝贵材料。因此,我强烈建议不要这样做。但是设置一个微小的障碍来阻止用户复制内容?而且还弄乱键盘交互?请不要像那样对用户不友好。
我很好奇,你认为哪些行为不友好?DRM?CCTV?密码?这些只是保护财产的必要措施。
不过,我完全理解你对其他一切的看法,你提供了一些很好的示例,说明何时使用它以及何时可能不希望在
<aside>
上使用它。今年 3 月,我做了一个书签来覆盖网站禁用文本选择的情况(Twitter 上有人建议如何阻止用户复制文本,这简直是不可取的)。
https://adrianroselli.com/2022/03/youre-unselectable.html
随着 WCAG 2.2 越来越接近完成,成功标准 3.3.7:可访问身份验证 和 成功标准 3.3.9:冗余条目 都将用户选择和复制文本的能力识别为满足它们的方法。禁用选择文本的能力,除了对用户不友好之外,还可能在某些情况下产生 WCAG 错误。
如果文本被模糊,显然不应被访问(因为它是免费的,或者其他原因),链接不可聚焦等,它是否仍然被视为文本?它是否应该被视为任何东西?
我只是不明白不友好的事情。如果有人试图通过不付费来破解你的系统,他们不应该期望遇到敌意吗?
Daniel,如果文本不应被访问,那么模糊它并不能阻止它被访问。Dev tools 或者 view-source 会很快绕过它。屏幕阅读器仍然可以访问它,没有任何提示它被模糊,并且仍然会找到那些不可聚焦的链接(除非使用一些 ARIA 技巧)。
如果它通过网络发送,那么它就是为用户准备的。如果网站希望用户付费才能获取该内容,那么不要将该内容发送到他们的电脑上。不要浪费用户的带宽和 CPU 周期,仅仅是为了指责他们“黑掉”你已经选择发送给他们的东西。
我构建了许多 SPA,并且我的最小样板代码的一部分是 body {user-select: none;},即默认情况下禁用文本选择。
然后,当我特别想让用户能够选择内容时,我重新添加它……我发现这种情况并不常见。
那个付费墙代码片段太棒了!这是一个五分钟的解决方案,适用于 99% 的用例。谢谢您。
是的,我认为大约 99% 的用例是正确的。开发人员可以轻松绕过付费墙,但他们只是少数。
就我而言,我发现自己在使用 Electron 等开发一些应用程序时,经常使用 user-select: none,当我尝试获得原生应用程序的行为时,而不是通常的互联网行为,即能够选择屏幕上的所有内容。
例如,对于应用程序 UI 本身的一部分文本(如工具栏或侧边菜单),我认为不允许选择文本是可以的。
但是对于其他区域,例如聊天应用程序的消息提要,我允许我的用户选择文本。
说得太对了!:)
user-select: none
绝不是任何形式的复制保护。它唯一能做的事情就是通过禁用完全合法的浏览器功能来惹恼你的潜在客户。
付费墙应该在服务器端实现,你不应该将付费内容发送给每个人。如果你在一个团队中工作,你应该与后端人员讨论这个问题。如果你想保护你自己的网站上的内容,并且你无法自己修改服务器,那么可以考虑聘请可以修改的人,或者使用 Patreon 或类似的网站来托管你的付费内容。
如果你想提供付费内容的模糊预览,那么有办法做到这一点,而无需将实际内容发送给每个人。(在服务器端渲染模糊图像/发送无意义的文本而不是实际内容/等等。现在你就可以合法地在上面使用
user-select: none
,因为选择和复制它没有任何意义)。无论如何,不要仅仅在前端实现“复制保护”,这是行不通的。大型企业花费数十亿美元在像 Widevine 这样的复杂技术上(它仍然需要服务器)是有原因的。CSS 和 JS 不能用于在浏览器中实现 DRM。
上下文菜单包含的功能远远不止“复制”。除了用包含与您的应用程序相关的功能的自定义上下文菜单替换它以外,出于任何原因禁用它都是对用户不友好的。
大多数情况下,单独使用
user-select: none
都是一个坏主意,会导致网站和应用程序出现故障。简要提到了“选择并不一定意味着复制”,但你并不知道。就我而言,阻止选择文本会让查找字典中的单词或搜索它变得更难(因为你需要自己重新输入单词或短语)。
我这样做,当我复制东西(到一个私人的笔记应用程序)时,我通常希望它们尽可能地逐字记录。图像、表情符号等都是内容的一部分。我会让接收应用程序决定它支持什么。
而诸如“链接作为按钮是反模式,或者说让我们让它们更难使用”之类的话,至少可以说令人震惊。