6041

For anchors that act like buttons (for example, the buttons on the sidebar of this Stack Overflow page titled Questions, Tags, and Users) or tabs, is there a CSS standard way to disable the highlighting effect if the user accidentally selects the text?

I realize that this could be done with JavaScript and a little googling yielded the Mozilla-only -moz-user-select option.

Is there a standard-compliant way to accomplish this with CSS, and if not, what is the "best practice" approach?

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 10
    can elements within the element witch has highlighting disabled, have highlighting enabled with in css in the style or class attribute? or in other words, are there other values for -webkit-user-select ect. other than just none? –  Mar 14 '11 at 21:18
  • 10
    Related: http://stackoverflow.com/questions/16600479/how-do-you-override-moz-user-select-none-on-a-child-element = how to allow only some of the child elements to be selected – JK. May 17 '13 at 02:36
  • 13
    There a bug in some browsers where doing "Select All" (CTRL+A and CMD+A) still selects things. This can be fought with a transparent selection color: `::selection { background: transparent; } ::-moz-selection { background: transparent; }` – DaAwesomeP Dec 12 '14 at 01:03
  • 3
    In year 2017, it is better way to use `postcss` and `autoprefixer` and set browser version, then `postcss` make everything cool. – AmerllicA Dec 06 '17 at 11:47
  • 1
    The user interface changed. In 2019, all three mentioned items are now in a hamburger menu in the upper left. *"Tags"* and *"Users"* are in there, and "Questions" is now called "Stack Overflow" (with an icon in front). – Peter Mortensen Nov 24 '19 at 12:23
  • `pointer-events: none;` worked for me in `iframe` – Manohar Reddy Poreddy Sep 10 '22 at 11:04
  • Please never do this on actual text (I understand buttons or other small elements might need this). Highlighting text as you read is an important coping strategy for dyslexia, and disabling it makes your webpage harder to read for those individuals. – Aaron Aug 09 '23 at 16:34

45 Answers45

8514

UPDATE January, 2017:

According to Can I use, the user-select + -webkit-user-select for Safari is enough to achieve desired behavior in all major browsers.


These are all of the available correct CSS variations:

.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>

Note that user-select is in standardization process (currently in a W3C working draft). It is not guaranteed to work everywhere and there might be differences in implementation among browsers. Also, browsers can drop support for it in the future.


More information can be found in Mozilla Developer Network documentation.

The values of this attribute are none, text, toggle, element, elements, all and inherit.

Julian Wagner
  • 674
  • 6
  • 16
Blowsie
  • 40,239
  • 15
  • 88
  • 108
  • 42
    nice code molokoloco :D , although I personally would stay well away from using it, as sometimes you may need the values different for different browsers, and it relys on JavaScript. Making a class and adding it to your element or applying the css to your type of element in your style-sheet is pretty bullet proof. – Blowsie Jan 14 '11 at 13:07
  • 67
    'user-select'- Values: none | text | toggle | element | elements | all | inherit - http://www.w3.org/TR/2000/WD-css3-userint-20000216 – Blowsie Mar 21 '11 at 09:44
  • 368
    this is ridiculous! so many different ways to do the same thing. let's make a new standard for user selects. we will call it `standard-user-select`. then we won't have these problems. although for backwards compatibility we should include the others as well. so now the code becomes `-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;`. ah, much better. – Claudiu Sep 04 '12 at 16:19
  • 5
    According to caniuse it seems that it doesn't need those prefixes anymore. – aderchox Jul 16 '21 at 11:16
  • 3
    @aderchox In that case, caniuse.com is wrong. I still need the `-webkit-user-select: none;` line using Safari on iOS 15.1. – Tamás Sengel Oct 30 '21 at 07:55
  • Instead of putting all that in a class I add it to `html, body { ... here... }` to apply it globally. Doesn't seem to be causing any problems so far. – Mark Feldman Mar 11 '22 at 11:54
  • `-webkit-user-select: none;` also disables macOS Live Text. To get rid of the text cursor though, you will need an additional `cursor: default`. – Martin Jul 18 '22 at 09:53
  • Actually `user-select` doesn’t work on Safari, you still have to use the `-webkit` prefix. See the little yellow sticky on the green cells on CanIuse – Julian Wagner Aug 18 '22 at 09:36
  • September 2023: Safari still need the `-webkit-` prefix. What is worse: `.style.webkitUserSelect = 'none'` is deprecated and sets `user-select: none`. One workaround is to use `.setAttribute("style", "-webkit-user-select: none; -webkit-touch-callout: none;")` – Wolle Sep 01 '23 at 06:57
950

In most browsers, this can be achieved using proprietary variations on the CSS user-select property, originally proposed and then abandoned in CSS 3 and now proposed in 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;
}

For Internet Explorer < 10 and Opera < 15, you will need to use the unselectable attribute of the element you wish to be unselectable. You can set this using an attribute in HTML:

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

Sadly this property isn't inherited, meaning you have to put an attribute in the start tag of every element inside the <div>. If this is a problem, you could instead use JavaScript to do this recursively for an element's descendants:

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"));

Update 30 April 2014: This tree traversal needs to be rerun whenever a new element is added to the tree, but it seems from a comment by @Han that it is possible to avoid this by adding a mousedown event handler that sets unselectable on the target of the event. See http://jsbin.com/yagekiji/1 for details.


This still doesn't cover all possibilities. While it is impossible to initiate selections in unselectable elements, in some browsers (Internet Explorer and Firefox, for example) it's still impossible to prevent selections that start before and end after the unselectable element without making the whole document unselectable.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • 34
    you should remove the * selector from your example, its really in-efficient and there really isnt any need to use it in your example is there? – Blowsie Jan 14 '11 at 13:15
  • 71
    @Blowsie: I don't think so: the CSS 2 spec states that `*.foo` and `.foo` are precisely equivalent (in the second case, the universal selector (`*`) is implied), so barring browser quirks, I can't see that including the `*` will harm performance. It's a long-standing habit of mine to include the `*`, which I originally started doing for readability: it explicitly states at a glance that the author intends to match all elements. – Tim Down Jan 14 '11 at 13:24
  • 40
    oooh after some further reading, it seems * is only un-effiecient when using it as the key (the righmost selector) ie .unselectable * . Further info here http://code.google.com/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors – Blowsie Jan 14 '11 at 13:49
  • 22
    Instead of using the class="unselectable", just use the attribute selector [unselectable="on"] { … } – Chris Calo Jan 26 '12 at 19:39
232

Until CSS 3's user-select property becomes available, Gecko-based browsers support the -moz-user-select property you already found. WebKit and Blink-based browsers support the -webkit-user-select property.

This of course is not supported in browsers that do not use the Gecko rendering engine.

There is no "standards" compliant quick-and-easy way to do it; using JavaScript is an option.

The real question is, why do you want users to not be able to highlight and presumably copy and paste certain elements? I have not come across a single time that I wanted to not let users highlight a certain portion of my website. Several of my friends, after spending many hours reading and writing code will use the highlight feature as a way to remember where on the page they were, or providing a marker so that their eyes know where to look next.

The only place I could see this being useful is if you have buttons for forms that should not be copy and pasted if a user copy and pasted the website.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
X-Istence
  • 16,324
  • 6
  • 57
  • 74
  • This may be necessary for embedded devices. i.e. a device where a browser is used for rendering the UI. – Tim Kersten Nov 04 '09 at 12:05
  • 36
    Another reason this is needed is Shift-clicking to select multiple rows in a grid or table. You don't want to to highlight the text, you want it to select the rows. – Gordon Tucker Jan 06 '10 at 16:08
  • 38
    Highly interactive web app with a lot of drag & drop... accidental highlighting is a big usability problem. – Marc Hughes Jun 03 '14 at 21:08
207

A JavaScript solution for Internet Explorer is:

onselectstart="return false;"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pekka
  • 442,112
  • 142
  • 972
  • 1,088
156

If you want to disable text selection on everything except on <p> elements, you can do this in CSS (watch out for the -moz-none which allows override in sub-elements, which is allowed in other browsers with 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;
}
James Donnelly
  • 126,410
  • 34
  • 208
  • 218
Benjamin Crouzier
  • 40,265
  • 44
  • 171
  • 236
  • 13
    Make sure you also make input fields selectable: `p, input { -webkit-user-select: text; -khtml-user-select: text; -moz-user-select: text; -o-user-select: text; user-select: text; }` – joshuadelange Jul 07 '11 at 22:39
  • 12
    Be very wary about turning off browser UI expectations on ALL code except for one item. What about list items
  • text, for example? – Jason Nov 12 '11 at 07:13
  • Just an update... according to MDN since Firefox 21 `-moz-none` and `none` are the same. – Kevin Fegan Dec 25 '13 at 15:56
  • 2
    For this you may add cursor:default and cursor:text respectively : ) – T4NK3R Jul 14 '14 at 17:14
  • *THE* bomb. That is to say. THE END. ````ul>* { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: -moz-none; -o-user-select: none; user-select: none; }```` [selects everything in an unordered list, and makes it un-selectable, rather than trashing the whole view tree.] Thanks for the lesson. My button list is looking great, and responding correctly to screen tapping and pressing, rather than launching an IME (android clipboard widgets). – Hypersoft Systems Sep 12 '19 at 06:54