CSS позволяет управлять, поведением и внешним видом выделенного текста на страницах HTML-документа. Это может помочь улучшить юзабилити в определенных ситуациях и добавить немного визуального чутья.
Выделить всё
Иногда бывает полезно, чтобы весь текст в элементе автоматически выделялся при нажатии на него. Это особенно удобно для текста, который копируется/вставляется полностью (фрагменты кода, одноразовые пароли, промокоды и т.д.).
Это можно сделать с помощью только простого CSS и без какого-либо JavaScript!
div {
-webkit-user-select: all; /* для Safari */
user-select: all;
}
Например, так:
Выделить всё… Затем выделить часть
Хотя это работает должным образом, можно заметить кое-что неприятное: невозможно выбрать что-то отдельное, кроме всего фрагмента кода. Хорошо бы первым кликом выбрать всё, но оставить возможность кликнуть ещё раз и выбрать только часть. Это можно сделать, всё ещё, с помощью только CSS.
Во-первых, надо использовать tabindex
, чтобы сделать HTML-элемент, содержащий текст, доступным для фокусировки. Это позволит CSS узнать о клике по HTML-элементу.
<code tabindex="0">Это фрагмент кода</code>
Теперь немного CSS.
code {
-webkit-user-select: all;
user-select: all;
}
code:focus {
animation: select 100ms step-end forwards;
}
@keyframes select {
to {
-webkit-user-select: text;
user-select: text;
}
}
Идея состоит в том, чтобы сначала установить для HTML-элемента CSS-свойство user-select: all
, а затем, когда фокус переместится на этот элемент, переключиться на «обычный» user-select: text
, чтобы текст можно было выбирать по частям. Выбор времени переключения – дело непростое. Если сделать переключение сразу после перемещения фокуса на элемент, то от user-select: all
не будет никакого эффекта, т.к. оно успеет сменить значение на text
. Поможет решить проблему animation
.
CSS-свойство user-select
можно анимировать. Оно дискретно анимированное, это означает, что нет постепенной интерполированной анимации, по истечении указанного времени происходит немедленный переход от одного состояния к другому. Поэтому, можно использовать animation
, чтобы отложить изменение поведения выделения текста до 100 миллисекунд после передачи фокуса HTML-элементу.
Предотвращение выделения текста
CSS можно использовать ещё и для того, чтобы сделать текст в элементе недоступным для выбора, т.е. запретить выделение текста.
label {
-webkit-user-select: none;
user-select: none;
}
Это плохая идея для основного текста, но будет полезно для элементов управления, которые можно быстро переключать или «гневно щелкать» в настольных браузерах, поскольку двойной щелчок вызывает выбор текста и подсветку его выделения – выглядеть немного странно и дико.
Проверить можно в следующей демонстрации. Обратите внимание, как переключатель слева становится подсвеченным при быстром нажатии, а переключатель справа – нет.
Этот метод также работает с виджетами раскрытия содержимого (HTML-элемент details
) или фальшивыми кнопками – например, <div>
с обработчиком кликов на нём. Правда, использование настоящего элемента <button>
предпочтительнее не только с точки зрения семантики и доступности, но и потому, что текст в такой кнопке по умолчанию не может быть выделен, а это позволяет избежать проблемы с самого начала.
Выборочное выделение текста
Невыделяемый текст можно смешивать с выделяемым текстом. Невыделяемые части просто пропускаются при выборе текста и будут пропущены при копировании/вставке выделения.
В примере ниже используется user-select: none
на числовых маркерах сносок. Поэтому, когда выделенное копируется/вставляется, маркеры автоматически удаляются.
Но это работает не во всех браузерах. Safari (iOS и компьютер) и Android Chrome по-прежнему будут копировать маркеры.
Стилизация выделения
Стилизовать выделенный текст можно с помощью псевдоэлемента ::selection
. Однако настройки ограничены тремя CSS-свойствами: color
, background-color
и text-shadow
(в спецификации их больше, но всё портит поддержка свойств браузерами).
Вот пример стилизации выделенного текста в HTML-элементе <p>
.
p::selection {
color: #fffb07;
background-color: #ff063b;
text-shadow: 2px 2px #028e4a;
}
Чтобы увидеть результат, выделяйте текст в примере ниже.
Немного особенностей
Есть еще одна декларация user-select: contain
, которая должна ограничивать выделение текста внутри элемента, как это работает с <textarea>
. Однако, IE11 был последним браузером, который поддерживал это. В настоящее время значение contain
не поддерживают все современные браузеры.
Тем не менее, все редактируемые элементы (такие как <textarea>
) обрабатываются, как если бы они имели user-select: contain
. Псевдоэлементы ::before
и ::after
нельзя выбрать, как если бы у них было установлено user-select: none
. Изменить такое поведение не получится.
Всё вышенаписанное было про CSS, но всё-таки стоит упомянуть JavaScript в контексте выделения текста и копипасты.
Если нужен полный контроль над выделением текста, пригодится JavaScript Selection API. Если конечной целью является копирование/вставка текста, то JavaScript позволяет взаимодействовать с буфером обмена.