Selection and CSS

The skill of highlighting text and other objects was formed among computer users many years ago. We highlight the content of web pages for various reasons. Perhaps you need to copy the text and quote it somewhere, perhaps - it is simply easier for someone to read the text, highlighting its fragments. On mobile devices, however, highlighting something more difficult. For example, it annoys me. I don’t like highlighting the contents of web pages on the phone. This operation seems to be somehow "wrong." In this article I’ll talk about everything you need to know about styling selections with CSS. In particular, we will talk about the pseudo-element and the property



::selectionuser-select. This article aims to show everyone who wants CSS to work with selections, and how to use different methods to work with selections.

The basics


On MDN, you can learn that a pseudo-element ::selectionallows you to apply styles to parts of a document that has been selected by the user (for example, using the mouse).

To use it is ::selectionenough to use the following construction:

p::selection {
   color: #fff;
   background-color: #000
}



Selected text.

Here is an example with which you can experiment.

Properties Supported :: selection


It is worth noting that the pseudo-element ::selectiononly supports properties color, backgroundand text-shadow.

Customize your own selection effects


What if we need to make the selection look special? For example, so that the selection would have a certain height or some interesting background? Take a look at the following figure.


An example of a special selection of selection

This is possible, although it will require some effort. Here's how the selection shown above is made:

  • A pseudo-element is added, with the same text that we select. Then the pseudo-element is set to a property height: 50%and a white background color.
  • The pseudo-element is located above the source text.

If you now select the text, then the pseudo-element will overlap 50% of the text vertically. This allows us to simulate the effect we need.

p {
  position: relative;
  color: #fff;
}

p:after {
  content: attr(data-content);
  position: absolute;
  color: #000;
  top: 0;
  left: 0;
  width: 100%;
  height: 50%;
  background-color: #fff;
}

p::selection {
  background: rgba(76, 125, 225, 0.18);
}

I learned about this technique here .

Another option for this selection is presented below. Here, instead of a solid selection, I implemented the selection as a CSS gradient. The point here is to use a white gradient with a height of 50% and to fill the element once with the background image by using the value no-repeatwhen setting the property background.

h1:after {
  content: attr(data-content);
  position: absolute;
  color: #000;
  top: 0;
  left: 0;
  width: 100%;
  background: linear-gradient(#fff, #fff) top/100% 50% no-repeat;
}

The following figure illustrates this technique.


Implementing Gradient Highlighting

Hopefully I was able to clearly explain this idea. Here is a working example.

Animating Selection


Working on the previous example, I asked the following question: "Is it realistic to animate the selection?". For example, in the process of selecting text, the height of the selection is 50%. And when the mouse pointer is moved to the side, the height of the selection increases to 80%. How to do it? But like this:

p {
    transition: background 0.3s ease-out;
}

p:hover:after {
  background-size: 100% 80%;
}



Text in the selection process


Text after selection is complete

Here is a video that demonstrates animated selection.

Multiline text


The above selection adjustment technique, unfortunately, is not suitable for multi-line text. In order to, nevertheless, implement something similar for such text, you need to resort to the capabilities of JavaScript and put each word in an inline (lowercase) element, for example, in <span>. After each word appears in its own element <span>, a pseudo-element must be added to each of these elements. And after that, the effect described above can be applied to multiline text.

Here is a script to put each word in a <span>container:

let paragraph = document.querySelector(".text");
const words = paragraph.textContent.split(" ");

paragraph.innerHTML = "";

words.forEach(function (word) {
  let wordItem = document.createElement("span");
  wordItem.setAttribute("data-word", word);
  wordItem.innerHTML = word + " ";
  paragraph.appendChild(wordItem);
});

After that, the elements <span>must be stylized. Then to each of them you need to add a pseudo-element:

span {
    position: relative;
    font-size: 1.25rem;
    line-height: 1.4;
  }

  span::after {
    content: attr(data-word);
    position: absolute;
    left: 0;
    right: 0;
    top: -0.28em;
    height: 75%;
    padding-top: 0.14em;
    background: #fff;
    pointer-events: none;
  }

  span::selection {
    background: rgba(#4C7DE1, 0.18);
  }

If you look at this design in practice, it turns out that it works, but not quite as you might expect. An example of multi-line text highlighting is shown below. You may notice that the selection looks patchy.


Inhomogeneous selection

I would say that such a multi-line selection is not very good, and that it should not be used on a global scale. Perhaps it should be used only, say, to organize the selection of a particular paragraph.

Here, with such a selection, you can experiment.

Creative use :: selection and text-shadow


Since one of the properties that the pseudo-element supports ::selectionis text-shadowthat we can try to achieve some interesting effects using several shadows of the text. We are exploring the possibilities that this idea opens before us.

▍ Highlight with long shadows



Selected text casts long shadows.

Here's how to implement this effect:

p::selection {
    color: #444444;
    background: #ffffff;
    text-shadow: 1px 0px 1px #cccccc, 0px 1px 1px #eeeeee, 2px 1px 1px #cccccc, 1px 2px 1px #eeeeee, 3px 2px 1px #cccccc, 2px 3px 1px #eeeeee, 4px 3px 1px #cccccc, 3px 4px 1px #eeeeee, 5px 4px 1px #cccccc, 4px 5px 1px #eeeeee, 6px 5px 1px #cccccc, 5px 6px 1px #eeeeee, 7px 6px 1px #cccccc;
}

▍ Outline text effect



Selected text becomes contour

This idea I found in this article. We are talking about the fact that using the propertytext-shadowyou can simulate the effect of the outline text.

p::selection {
    color: #fff;
    text-shadow
        -1px -1px 0 #000,  
        1px -1px 0 #000,
        -1px 1px 0 #000,
        1px 1px 0 #000;
}

▍ Blur effect



Selected text looks blurry.

Another interesting effect that can be applied to selected text is to blur the text. The bottom line is to use the property when setting the color of the textcolor: transparent. The shadows set with the helptext-shadowwill not disappear anywhere, which will give the desired effect.

p::selection {
  color: transparent;
  text-shadow: 0 0 3px #fff;
}

I’m sure that you yourself will be able to come up with many more examples of text-shadowstyling selections. This property gives us unlimited possibilities.

▍Shadow texts and performance


It is not recommended to use too complex styles when customizing text-shadow. The fact is that excessive enthusiasm for this property leads to performance problems. Here's a video showing one example of such issues.


Using very sophisticated styles to customize text selection

The neon effect presented here is very complex. Please note that when this text is selected, there is a noticeable delay between the moment the text is selected and the moment the stylization is applied. In addition, pay attention to the fact that what should not appear on top and left. Therefore, I ask you to use ittext-shadowcarefully.

Do form elements stand out?


A short answer to the question in the title of this section will sound “yes.” It seems to me that this is wrong: you select the page, but it turns out that the content inside the input fields is also highlighted. Here is how it looks.


The content inside the input fields is highlighted.

Here, the text inside the button can also be selected. In the section devoted touser-select, we will talk about whether or not to allow users to highlight the forms of elements.

Here is an example.

Investigating the user-select property


The property user-selectallows us to set the ability to select specific text by the user. This property may be useful for disabling the ability to select text, which may be useful to limit the user's ability to select materials located next to each other. Here is a standard that describes user-select.

This property can take the following values: none, auto, text, contain, all.

User-select use cases


▍Text and icon


If the element has text and an icon - in the form of a symbol or icon taken from some font, then this icon will be highlighted when the text is selected. Consider the example shown in the following figure.


Button with text and icon

Here is the code for this button:

<button>Our Services<span aria-hidden="true">▼</span></button>

When you select this item, it looks like the one shown below.


Dedicated button

This is completely unnecessary. Please note that the markup uses an attributearia-hiddenthat hides the icon from screen readers. In order to solve the problem of highlighting what you do not need to highlight, we can use the following style:

button span[aria-hidden="true"] {
    user-select: none;
}

This allows you to prohibit the selection of the icon. And, at the same time, we bind the selection ban to the attribute aria-hidden. As a result, everything that should not stand out, most likely, should not be visible to screen readers.

▍ Flags


This behavior of the flags annoys me when, by setting or unchecking a flag, I accidentally select the text of its description. Here is how it looks.


The text of the flag description is selected randomly. You can

solve this problem by styling the element<label>as follows:

label {
    user-select: none;
}

▍ Highlight all text


The value allthat a property can take user-selectallows you to achieve an interesting effect. If the parent element has this property with such a value, then all the text contained in such an element can be selected with one click. This can be useful for working with text content, which should be highlighted in its entirety. For example, to highlight code fragments available on a page:

.embed-code {
    user-select: all;
}

A fragment of text designed in such a style can be selected with one click on it.

Web applications


The web application should be perceived by the user as a real application. Is it possible to select button text in regular applications? No you can not. It is important that web applications reflect the familiar features of regular applications, even if they are designed using HTML and CSS.

Consider a few examples from life.

▍Slack


In Slack, you can highlight labels and input fields. However, button texts are not highlighted.


Button captions are not highlighted.

Here is another example.


The signature in the title bar of the modal window is highlighted

. The date of the chat cannot be highlighted.


The date cannot be allocated

In general - it seems strange to me that in the application you can select some texts that, it would seem, should not support the selection. There are places in the Slack interface where it is useduser-select: none, but there are fewer such places than you might expect. For example, to me, as a user, there is no benefit from highlighting the title of a modal window.

▍Notion


The approach to the selection of elements implemented in Notion, I like more. This web application is more like a real application, rather than a website, any part of which can be highlighted.


What should not stand out does not stand out.

Not a single fragment of text is highlighted from this picture. This is exactly what you can expect from an application.

Do not use global selection disable


It is not recommended to disable selection globally. When you use disabling selection, try to disable it only for elements for which it does not make sense. To do this, you can create a helper class. For example - this:

.disable-selection {
    -webkit-user-select:text;
    -moz-user-select:text;
    -ms-user-select:text;
    user-select:text;
}

Bad pattern


There is one UX pattern that I really dislike. It consists in showing a warning when trying to highlight text. This annoys and makes the user feel as if they are trying to control his interaction with the site. An example of this pattern is shown below.


Disable highlighting with notification display

Please do not do this.

Highlight on mobile devices


There is a property -webkit-touch-calloutfor iOS Safari that should turn off the display of the standard tooltip displayed when text is selected. I tried to use this property, but it does not work.

p {
    -webkit-touch-callout: none;
}

Styles ::selectiondon't work either.

And the property user-select: noneworks as expected.

I tried to find a real example illustrating this problem. I copied a piece of text from Wikipedia. At the same time, the text that was completely unnecessary to me was copied (listen). This is annoying.


Together with the useful text, it is copied and (listen)

Instead of allowing the user to copy this “listen”, it would be better to add a style to this elementuser-select: none. As a result, when copying text containing this element, it will not be copied.

Summary


Here we looked at methods for customizing the highlighting of web page elements using CSS. You may be interested in looking at this material.

Dear readers! How do you set up text selection in your projects?


All Articles