本文为转载文章,如果涉及侵权,请联系 suziwen1@gmail.com,会第一时间删除
转载自: https://codersblock.com/blog/using-css-to-control-text-selection/
CSS lets you control how text selection behaves and appears on your pages. This can help you improve usability in certain situations and add a little bit of visual flair. Let’s dive in!
Select All
Sometimes it’s nice to have all the text in an element automatically selected when you click on it. This is particularly handy for text that is copied/pasted in full (code snippets, one-time passwords, promotional codes, etc.).
You can accomplish this with some simple CSS. No JavaScript required!
- 1div {
- 2 -webkit-user-select: all; /* for Safari */
- 3 user-select: all;
- 4}
Here’s a demo. Bad news, it doesn’t work on iOS. Good news, it degrades gracefully, so the text is still selectable.
Select All… Then Select Some
While this works as expected, you may notice something annoying: it is impossible to select anything less than the entire code snippet. Wouldn’t it be nice if the first click selected all, but you could still click again and select just a portion? CSS can do this.
First, use tabindex
to make the element holding the text focusable. This gives the CSS a way to know when the element has been clicked.
- 1<code tabindex="0">code snippet goes here</code>
Then comes the CSS.
- 1code {
- 2 -webkit-user-select: all;
- 3 user-select: all;
- 4}
- 5
- 6code:focus {
- 7 animation: select 100ms step-end forwards;
- 8}
- 9
- 10@keyframes select {
- 11 to {
- 12 user-select: text;
- 13 }
- 14}
The idea is to have user-select: all
on the element initially, then switch to the “normal” user-select: text
after the element has focus so that text can be freely re-selected. The tricky part is the timing. Do the switch immediately upon focus and user-select: all
is gone before it has a chance to do its job. That’s where animation
comes in.
Yes, user-select
is animatable! More specifically, it is discretely animatable, meaning there is no gradual interpolated animation, but rather an immediate cut from one state to another. Armed with this knowledge, we can use animation
to delay the change in select behavior until 100ms after focus. Perfect.
Again, the “select all” bit doesn’t work on iOS. Meanwhile, desktop Safari keeps the text as “select all”. This trick seems to work fine elsewhere, though.
Preventing Text Selection
You can also use CSS to make text in an element unselectable.
- 1label {
- 2 -webkit-user-select: none;
- 3 user-select: none;
- 4}
This is probably a bad idea for body text, but I’ve found it useful for controls that might be toggled quickly or “rage clicked” in desktop browsers, since double clicking causes text to be selected and highlighted, which can look a little weird sometimes.
See for yourself in the following demo. Notice how the toggle on the left becomes highlighted when rapidly clicked, while the one on the right doesn’t.
This technique also works on disclosure widgets. Fake buttons — like a <div>
with a click
handler on it — are another candidate. Bear in mind that using a real <button>
is preferable, not only for semantics and accessibility, but also because text in a <button>
is unselectable by default, avoiding the issue to begin with.
Selectively Selecting Text
Unselectable text can be mixed into selectable text. The unselectable bits are simply skipped over when text is selected and will be omitted when the selection is copied/pasted.
The demo below uses user-select: none
on the numerical footnote markers. So when you copy/paste, the markers are automatically removed for you.
Sadly, some browsers won’t play along. Safari (iOS and desktop) and Android Chrome will still copy the markers.
Styling the Selection
You can style text selections by targeting the ::selection
pseudo-element. However, your options are limited to 3 properties: color
, background-color
, and text-shadow
(there are more defined in the spec, but browsers don’t support them).
Here’s an example that styles the selected text in a <p>
.
- 1p::selection {
- 2 color: #fffaa5;
- 3 background-color: #f38630;
- 4 text-shadow: 2px 2px #31808c;
- 5}
Try selecting some text in the demo below to see the result. Unfortunately, iOS is the holdout once again, but everyone else should see fancier colors.
Odds and Ends
There’s another declaration, user-select: contain
, that is supposed to confine text selections to within an element, like you’d see with a <textarea>
. Oddly enough, IE11 was the last browser to support it. No modern browsers support it currently.
That said, all editable elements (such as <textarea>
) are treated as if they had user-select: contain
. And the ::before
and ::after
pseudo-elements are unselectable, as if they had user-select: none
. You cannot override these behaviors.
Going Further
This article is about CSS, but I would be remiss if I didn’t mention the relevant JavaScript.
If you want full control over text selections, with the ability to create and modify them at will, then check out the JavaScript Selection API. If the end goal is to copy/paste text, then you should know that JavaScript also allows you to interact with the clipboard.