如何禁用文本选择高亮显示

6069

对于像按钮一样的锚点(例如此 Stack Overflow 页面侧边栏上标题为“Questions”、“Tags”和“Users”的按钮)或选项卡,是否有CSS标准的方法来禁用高亮效果,以防用户意外选择文本?

我知道这可以通过JavaScript来实现,而且通过一些搜索可以找到仅适用于 Mozilla 的 -moz-user-select 选项。

是否有符合标准的CSS方法来完成此操作,如果没有,那么最佳实践是什么?


10
在CSS的样式或类属性中,禁用了高亮显示的元素内部的元素是否可以启用高亮显示?换句话说,除了"none"之外,-webkit-user-select等属性还有其他值吗? - user659576
10
相关:https://dev59.com/ymQn5IYBdhLWcg3wvpQV = 如何仅允许选择某些子元素。 - JK.
14
在一些浏览器中存在一个 bug,即执行“全选”(CTRL+A 和 CMD+A)仍会选择其他内容。这可以通过使用透明的选择颜色来解决:::selection { background: transparent; } ::-moz-selection { background: transparent; } - DaAwesomeP
3
在2017年,更好的做法是使用postcssautoprefixer,并设置浏览器版本,然后postcss会使一切变得很棒。 - AmerllicA
1
用户界面已更改。在2019年,所有三个提到的项目现在都在左上角的汉堡菜单中。其中包括“标签”和“用户”,而“问题”现在称为“Stack Overflow”(前面带有图标)。 - Peter Mortensen
显示剩余2条评论
45个回答

8534

2017年1月更新:

根据 Can I use 网站,user-select-webkit-user-select(适用于Safari浏览器) 即可在所有主流浏览器中实现所需的行为。


以下是所有可用的正确 CSS 变体:

.noselect {
  -webkit-touch-callout: none; /* iOS Safari */
    -webkit-user-select: none; /* Safari */
     -khtml-user-select: none; /* Konqueror HTML */
       -moz-user-select: none; /* Old versions of Firefox */
        -ms-user-select: none; /* Internet Explorer/Edge */
            user-select: none; /* Non-prefixed version, currently
                                  supported by Chrome, Edge, Opera and Firefox */
}
<p>
  Selectable text.
</p>
<p class="noselect">
  Unselectable text.
</p>

请注意,user-select正在标准化过程中(目前在W3C工作草案中)。它不能保证在所有地方都起作用,并且在不同的浏览器实现之间可能存在差异。此外,浏览器未来可能会取消对其的支持。
更多信息可以在Mozilla开发者网络文档中找到。
该属性的值包括nonetexttoggleelementelementsallinherit

42
不错的代码molokoloco :D,虽然我个人会远离使用它,因为有时您可能需要针对不同的浏览器使用不同的值,并且它依赖于JavaScript。创建一个类并将其添加到您的元素中,或者在样式表中应用CSS到您的元素类型中,是相当可靠的。 - Blowsie
67
'user-select' - 值:none | text | toggle | element | elements | all | inherit - http://www.w3.org/TR/2000/WD-css3-userint-20000216'user-select' 是一个 CSS 属性,用于控制用户是否可以选择元素中的文本。它有七个取值,分别是:
  • none:禁止选择文本。
  • text:允许选择文本,但不包括可编辑内容(如输入框)。
  • toggle:允许选择文本,但仅在用户显式地请求时才允许选择。
  • element:只允许选择元素,不包括其中的文本。
  • elements:允许选择元素和其中的文本。
  • all:允许选择所有内容。
  • inherit:从父元素继承 'user-select' 属性。
该属性最初定义于 W3C 的 2000 年 CSS 用户界面工作草案中。
- Blowsie
372
这太荒谬了!做同样的事情有这么多不同的方法。让我们为用户选择制定一个新的标准。我们将称其为“standard-user-select”。然后我们就不会遇到这些问题了。虽然为了向后兼容,我们应该同时包含其他方式。现在代码变成了-webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; standard-user-select: none;。啊,好多了。 - Claudiu
5
根据 caniuse 网站的显示,似乎不再需要使用这些前缀了。 - aderchox
3
在这种情况下,caniuse.com是错误的。我仍然需要在iOS 15.1上使用Safari时添加“-webkit-user-select:none;”一行代码。 - Tamás Sengel
显示剩余4条评论

953
在大多数浏览器中,可以使用CSS的专有变体来实现这一点user-select属性,最初在CSS 3中提出并被放弃,现在在CSS UI Level 4中提出:
*.unselectable {
   -moz-user-select: none;
   -khtml-user-select: none;
   -webkit-user-select: none;

   /*
     Introduced in Internet Explorer 10.
     See http://ie.microsoft.com/testdrive/HTML5/msUserSelect/
   */
   -ms-user-select: none;
   user-select: none;
}

对于Internet Explorer < 10和Opera < 15,您需要使用元素的unselectable属性才能使其不可选。您可以在HTML中使用属性设置:

<div id="foo" unselectable="on" class="unselectable">...</div>

遗憾的是,这个属性不是继承的,这意味着您需要在<div>内的每个元素的开始标签中放置一个属性。如果这是一个问题,您可以使用JavaScript递归地为元素的后代执行此操作:
function makeUnselectable(node) {
    if (node.nodeType == 1) {
        node.setAttribute("unselectable", "on");
    }
    var child = node.firstChild;
    while (child) {
        makeUnselectable(child);
        child = child.nextSibling;
    }
}

makeUnselectable(document.getElementById("foo"));

2014年4月30日更新:这种树遍历需要在树中添加新元素时重新运行,但是根据@Han的评论,通过添加一个mousedown事件处理程序来设置事件目标上的unselectable可以避免这种情况。详情请参见http://jsbin.com/yagekiji/1


这仍然不能涵盖所有可能性。虽然在无法选择的元素中无法启动选择,但在某些浏览器中(例如Internet Explorer和Firefox),仍然无法防止从不可选择元素之前开始并在其之后结束的选择,而不使整个文档不可选择。


34
你应该从例子中删除 * 选择器,它非常低效,在你的例子中没有必要使用它,对吗? - Blowsie
71
@Blowsie:我不这样认为:CSS 2 规范表明 *.foo.foo 是完全等价的(在第二种情况下,普通选择器(*)被隐含),因此除非存在浏览器怪异行为,否则我认为包含 * 不会影响性能。我的一个长期习惯是包含 *,最初是为了可读性:它清楚地表明作者打算匹配所有元素。 - Tim Down
40
经过进一步阅读,似乎仅在将*用作键(最右侧选择器)时,即.unselectable 时,才是低效的。更多信息请参见http://code.google.com/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors - Blowsie
22
不要使用class="unselectable",而是使用属性选择器[unselectable="on"] { … }。 - Chris Calo

233

在CSS 3的user-select属性可用之前,基于Gecko的浏览器支持你已经发现的-moz-user-select属性。 基于WebKit和Blink的浏览器支持-webkit-user-select属性。

当然,不使用Gecko渲染引擎的浏览器不支持此功能。

没有符合“标准”的快速简便方法来实现它; 使用JavaScript是一种选择。

真正的问题是,为什么要让用户无法突出显示并可能复制和粘贴某些元素? 我从未遇到过任何时候想要不让用户突出显示我的网站某个部分的情况。 在阅读和编写代码多个小时后,我的几位朋友将使用突出显示功能作为记住页面上位置或提供标记以便他们的眼睛知道下一步要查看的位置的方式。

唯一我能想到这有用的地方是,如果你有表单按钮,希望在用户复制和粘贴网站时无法复制并粘贴表单按钮。


这可能对嵌入式设备是必要的,例如使用浏览器来呈现用户界面的设备。 - Tim Kersten
36
这是必需的另一个原因是在网格或表格中Shift+单击以选择多行。你不想突出显示文本,而是想选择行。 - Gordon Tucker
40
高度互动的Web应用程序具有大量拖放操作,意外高亮显示是一个很大的可用性问题。 - Marc Hughes

208

Internet Explorer 的 JavaScript 解决方案是:

onselectstart="return false;"

61
不要忘记 ondragstart - Mathias Bynens

157

如果您想在除了 <p> 元素以外的其他元素上禁用文本选择,您可以在 CSS 中进行设置(注意 -moz-none 可以允许子元素覆盖,而其他浏览器中的 none 不允许):

* {
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: -moz-none;
    -o-user-select: none;
    user-select: none;
}

p {
    -webkit-user-select: text;
    -khtml-user-select: text;
    -moz-user-select: text;
    -o-user-select: text;
    user-select: text;
}

13
请确保将输入字段设置为可选择:p,input { -webkit-user-select: text; -khtml-user-select: text; -moz-user-select: text; -o-user-select: text; user-select: text; } - joshuadelange
12
除了一个项目之外,关闭所有代码的浏览器UI期望时要非常小心。例如,对于列表项<li/>文本,该怎么处理? - Jason
只是一个更新...根据MDN的说法,自Firefox 21以来,-moz-nonenone是相同的。 - Kevin Fegan
2
为此,您可以分别添加cursor:default和cursor:text:) - T4NK3R
就是炸弹。也就是说,结束了。 -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: -moz-none; -o-user-select: none; user-select: none; }```` [选择无序列表中的所有内容,并使其不可选择,而不是破坏整个视图树。] 感谢您的教训。我的按钮列表看起来很棒,并且对屏幕轻触和按压做出了正确的响应,而不是启动 IME(Android 剪贴板小部件)。 - Hypersoft Systems

139
在之前的答案中,选择已经停止了,但用户仍然认为可以选择文本,因为光标仍然会改变。如果要使其保持静态,您需要设置CSS光标:

.noselect {
    cursor: default;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
<p>
  Selectable text.
</p>
<p class="noselect">
  Unselectable text.
</p>

这将使您的文本完全平坦,就像在桌面应用程序中一样。


“Flat”相对于什么? - kojow7
与“分层”相反。而不是文本浮在其他元素上方。这类似于SVG和PNG图像之间的区别。 - Yeti
4
很惊讶地发现,在2019年,Firefox仍需要供应商前缀。我轻视地只使用了 user-select: none;,认为标准现在应该被采用了,但可悲的是它还没有。这让你想知道标准委员会的人们可能仍在争论什么。“不,伙计们... 我真的认为它应该是user-select:cant;,因为更具描述性,你知道吗?” “我们已经讨论过了,迈克。我们必须省略撇号,这样做是错误的!” “够了,大家!我们将于下个月再次研究这个问题。标准委员会会议休会!” - Mentalist

121

你可以在Firefox和Safari中这样做(Chrome也可以?)

::selection { background: transparent; }
::-moz-selection { background: transparent; }

131
我不建议这样做,因为它实际上并不能解决问题,只是隐藏了文本选择。这可能会导致糟糕的可用性,因为如果我在页面上拖动光标,则可能选择任意文本而不知道。这可能会导致各种奇怪的可用性“故障”。 - Keithamus
2
无法在具有透明区域的PNG图像上工作:它们总是选择浅蓝色... 有什么解决方法吗? - AvL

91

WebKit的解决方法:

/* Disable tap highlighting */
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);

我在一个 CardFlip 的例子中找到了它。

1
在安卓的Chrome 42中,使用transparent代替rgba也可以起作用。 - Clint Pachl

87

我喜欢混合使用CSS和jQuery的解决方案。

要使<div class="draggable"></div>中的所有元素都无法选择,请使用以下CSS:

.draggable {
    -webkit-user-select: none;
     -khtml-user-select: none;
       -moz-user-select: none;
        -ms-user-select: none;
         -o-user-select: none;
            user-select: none;
}

.draggable input {
    -webkit-user-select: text;
     -khtml-user-select: text;
       -moz-user-select: text;
         -o-user-select: text;
            user-select: text;
 }

然后,如果你正在使用jQuery,将以下代码放在$(document).ready()块内:

if (($.browser.msie && $.browser.version < 10) || $.browser.opera) $('.draggable').find(':not(input)').attr('unselectable', 'on');

我想你仍然希望所有输入元素都可以交互,因此使用:not()伪选择器。如果您不在意,可以使用'*'代替。

注意:Internet Explorer 9可能不需要这个额外的jQuery代码,因此您可能需要在其中添加版本检查。


6
使用 -ms-user-select: none; (适用于IE10),您的jQuery "if"语句应该是这样的:if (($.browser.msie && $.browser.version < 10) || $.browser.opera)。 - mhenry1384
8
jQuery.browser自1.3版本起已被弃用,并在1.9版本中删除 - http://api.jquery.com/jQuery.browser - WynandB
@Wynand 很好的观点。但是有什么“特性检测”可以确定使用哪个CSS属性呢? - Tom Auger
@TomAuger 你可以使用jQuery.support,它允许你检查单个特性:链接 - Aequanox
@PeterMortensen 但是 user-select: noneinput 元素上甚至不起作用?!?你仍然可以选择文本。我该如何使 user-select: none 在输入元素上起作用??? - oldboy
显示剩余2条评论

80
你可以使用CSS或JavaScript来实现这个功能。
在旧版浏览器(如旧版Internet Explorer)中,支持使用JavaScript的方式,但如果不是这种情况,请使用CSS的方式:
HTML/JavaScript:

<html onselectstart='return false;'>
  <body>
    <h1>This is the Heading!</h1>
    <p>And I'm the text, I won't be selected if you select me.</p>
  </body>
</html>

HTML/CSS:

.not-selectable {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none;
}
<body class="not-selectable">
  <h1>This is the Heading!</h1>
  <p>And I'm the text, I won't be selected if you select me.</p>
</body>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接