Подкаст CSS - 015: Псевдоклассы
Допустим, у вас есть форма регистрации для отправки электронного письма, и вы хотите, чтобы поле формы отображалось красной рамкой, если оно содержит недействительный адрес электронной почты. Как это сделать? Можно использовать CSS-псевдокласс :invalid
, один из множества псевдоклассов, предоставляемых браузером.
Псевдокласс позволяет применять стили на основе изменений состояния и внешних факторов. Это означает, что ваш дизайн может реагировать на пользовательский ввод, например, на неверный адрес электронной почты. Эти вопросы рассматриваются в модуле «Селекторы» , и этот модуль расскажет о них подробнее.
В отличие от псевдоэлементов, о которых вы можете узнать больше в предыдущем модуле , псевдоклассы привязываются к определенным состояниям , в которых может находиться элемент, а не к общим стилям частей этого элемента.
Интерактивные состояния
Следующие псевдоклассы применяются в зависимости от взаимодействия пользователя с вашей страницей.
:hover
Если у пользователя есть указывающее устройство, например, мышь или трекпад, и он наводит его на элемент, вы можете использовать это состояние с помощью :hover
для применения стилей. Это полезный способ указать, что с элементом можно взаимодействовать.
:active
Это состояние активируется при активном взаимодействии с элементом, например, при щелчке, до того, как щелчок будет отпущен. При использовании указывающего устройства, например, мыши, это состояние возникает в момент начала щелчка, но ещё не отпущенного.
:focus
, :focus-within
и :focus-visible
Если элемент может получить фокус, например <button>
, вы можете отреагировать на это состояние с помощью псевдокласса :focus
.
Вы также можете отреагировать, если дочерний элемент вашего элемента получает фокус, с помощью :focus-within
.
Фокусируемые элементы, такие как кнопки, будут отображать кольцо фокусировки, когда они находятся в фокусе, даже при нажатии. В такой ситуации разработчик применит следующий CSS:
button:focus {
outline: none;
}
Этот CSS-код удаляет кольцо фокусировки по умолчанию в браузере, когда элемент получает фокус, что создает проблему доступности для пользователей, перемещающихся по веб-странице с помощью клавиатуры. Если стиль фокусировки отсутствует, пользователи не смогут отслеживать текущий фокус при использовании клавиши Tab . С помощью :focus-visible
можно задать стиль фокусировки, когда элемент получает фокус с помощью клавиатуры, а также использовать правило outline: none
, чтобы предотвратить фокусировку при взаимодействии с ним указателя.
button:focus {
outline: none;
}
button:focus-visible {
outline: 1px solid black;
}
:target
Псевдокласс :target
выбирает элемент, id
которого соответствует фрагменту URL. Допустим, у вас есть следующий HTML-код:
<article id="content">
<!-- ... -->
</article>
Вы можете прикрепить стили к этому элементу, если URL содержит #content
.
#content:target {
background: yellow;
}
Это полезно для выделения областей, на которые можно было бы ссылаться напрямую, например, на основной контент веб-сайта, с помощью ссылки пропуска.
Исторические государства
:link
Псевдокласс :link
можно применить к любому элементу <a>
, имеющему значение href
, которое еще не было посещено.
:visited
Вы можете задать стиль для ссылки, по которой пользователь уже побывал, с помощью псевдокласса :visited
. Это состояние противоположно :link
, но из соображений безопасности доступно меньше CSS-свойств. Можно задать стиль только color
, background-color
, border-color
, outline-color
, а также для цветов fill
и stroke
SVG.
Порядок имеет значение
Если вы определяете стиль :visited
, его можно переопределить псевдоклассом ссылки как минимум с такой же специфичностью. Поэтому рекомендуется использовать правило LVHA для стилизации ссылок с псевдоклассами в определённом порядке: :link
, :visited
, :hover
, :active
.
a:link {}
a:visited {}
a:hover {}
a:active {}
Форма состояния
Следующие псевдоклассы могут выбирать элементы формы в различных состояниях, в которых эти элементы могут находиться во время взаимодействия с ними.
:disabled
и :enabled
Если элемент формы, например, <button>
, отключен браузером, вы можете подключиться к этому состоянию с помощью псевдокласса :disabled
. Псевдокласс :enabled
доступен и для противоположного состояния, хотя элементы формы также имеют :enabled
по умолчанию, поэтому вам может не понадобиться этот псевдокласс.
:checked
и :indeterminate
Псевдокласс :checked
доступен, когда поддерживающий элемент формы, такой как флажок или переключатель, находится в отмеченном состоянии.
Состояние :checked
— это бинарное (истина или ложь), но у флажков есть промежуточное состояние, когда они ни отмечены, ни сняты. Это состояние называется :indeterminate
.
Примером такого состояния является элемент управления «выбрать всё», который устанавливает все флажки в группе. Если пользователь затем снимет один из этих флажков, корневой флажок перестанет отображать состояние «все отмечены», поэтому его следует перевести в неопределённое состояние.
Элемент <progress>
также имеет неопределённое состояние, которое можно стилизовать. Обычно его используют для придания ему полосатого вида, чтобы показать, что неизвестно, сколько ещё нужно.
:placeholder-shown
Если поле формы имеет атрибут placeholder
и не имеет значения , псевдокласс :placeholder-shown
можно использовать для назначения стилей этому состоянию. Как только в поле появляется контент, независимо от наличия placeholder
, это состояние перестает применяться.
Состояния проверки
Вы можете реагировать на валидацию HTML-форм с помощью псевдоклассов, таких как :valid
, :invalid
и :in-range
. Псевдоклассы :valid
и :invalid
полезны в таких контекстах, как поле электронной почты, которое должно соответствовать pattern
, чтобы считаться валидным. Это состояние валидности значения можно показать пользователю, помогая ему понять, что он может безопасно перейти к следующему полю.
Псевдокласс :in-range
доступен, если входные данные имеют min
и max
значения, например, числовые входные данные , и значение находится в пределах этих границ.
С помощью HTML-форм можно определить, что поле является обязательным, с помощью атрибута required
. Псевдокласс :required
будет доступен для обязательных полей. Необязательные поля можно выбрать с помощью псевдокласса :optional
.
Выбор элементов по индексу, порядку и местоположению
Существует группа псевдоклассов, которые выбирают элементы в зависимости от их местоположения в документе.
:first-child
и :last-child
Если вам нужно найти первый или последний элемент, можно использовать :first-child
и :last-child
. Эти псевдоклассы вернут либо первый, либо последний элемент в группе родственных элементов.
:only-child
Вы также можете выбрать элементы, не имеющие родственных элементов, с помощью псевдокласса :only-child
.
:first-of-type
и :last-of-type
Вы можете выбрать :first-of-type
и :last-of-type
, которые на первый взгляд выглядят так, будто делают то же самое, что и :first-child
и :last-child
, но рассмотрим следующий HTML-код:
<div class="my-parent">
<p>A paragraph</p>
<div>A div</div>
<div>Another div</div>
</div>
И этот CSS:
.my-parent div:first-child {
color: red;
}
Ни один элемент не будет окрашен в красный цвет, поскольку первый дочерний элемент — это абзац, а не div. В этом контексте полезен псевдокласс :first-of-type
.
.my-parent div:first-of-type {
color: red;
}
Несмотря на то, что первый <div>
является вторым дочерним элементом, он все равно является первым типом внутри элемента .my-parent
, поэтому по этому правилу он будет окрашен в красный цвет.
:nth-child
и :nth-of-type
Вы не ограничены первыми и последними дочерними элементами и типами. Псевдоклассы :nth-child
и :nth-of-type
позволяют указать элемент с определённым индексом. Индексация в селекторах CSS начинается с 1.
Псевдоклассы :nth-last-child()
и :nth-last-of-type()
отсчитываются с конца, а не с начала.
В эти псевдоклассы можно передавать не только индекс. Если нужно выбрать все чётные элементы, можно использовать :nth-child(even)
.
Вы также можете создавать более сложные селекторы, которые находят элементы через равные интервалы, используя микросинтаксис An+B .
li:nth-child(3n+3) {
background: yellow;
}
Этот селектор выбирает каждый третий элемент, начиная с элемента 3. В этом выражении n
— это индекс, который начинается с нуля, а 3 ( 3n
) — это то, на что вы умножаете этот индекс.
Допустим, у вас есть 7 элементов <li>
. Первым выбранным элементом будет элемент 3, поскольку 3n+3
преобразуется в (3 * 0) + 3
Следующая итерация выберет элемент 6, поскольку n
теперь увеличилось до 1
, то есть (3 * 1) + 3)
. Это выражение работает как для :nth-child
, так и :nth-of-type
.
:nth-child()
и :nth-last-child()
также поддерживают синтаксис «of S», позволяющий фильтровать совпадения по селектору, аналогично :nth-of-type()
. li:nth-of-type(even)
эквивалентно :nth-child(even of li)
. В то время как :nth-of-type
позволяет фильтровать только по типу элемента (например, li
или p
), синтаксис «of S» позволяет фильтровать по любому селектору.
Если у вас есть таблица, возможно, стоит добавить полосы к каждой второй строке. Хотя можно выбрать каждую вторую строку с помощью tr:nth-child(even)
, это не сработает, если вы отфильтровываете некоторые строки. Если вы реализуете фильтрацию с помощью атрибута hidden
, можно добавить of :not([hidden])
к селектору, чтобы предварительно отфильтровать скрытые элементы перед выбором чётных строк.
tr:nth-child(even of :not([hidden])){
background: lightgrey;
}
Вы можете поэкспериментировать с этим типом селектора в этом тестере nth-child или в этом инструменте выбора количества .
:only-of-type
Наконец, вы можете найти единственный элемент определённого типа в группе одноуровневых элементов с помощью :only-of-type
. Это полезно, если вы хотите выбрать списки, содержащие только один элемент, или найти единственный выделенный жирным шрифтом элемент в абзаце.
Поиск пустых элементов
Иногда может быть полезно идентифицировать совершенно пустые элементы, и для этого тоже есть псевдокласс.
:empty
Если у элемента нет дочерних элементов, к ним применяется псевдокласс :empty
. Однако дочерние элементы — это не только HTML-элементы или текстовые узлы: они также могут быть пробелами, что может сбивать с толку при отладке следующего HTML-кода и возникновении вопросов, почему он не работает с :empty
:
<div>
</div>
Причина в том, что между открывающим и закрывающим <div>
есть пробелы, поэтому :empty
не будет работать.
Псевдокласс :empty
может быть полезен, если у вас ограниченный контроль над HTML-кодом и вы хотите скрыть пустые элементы, например, в WYSIWYG-редакторе. В данном случае редактор добавил лишний пустой абзац.
<article class="post">
<p>Donec ullamcorper nulla non metus auctor fringilla.</p>
<p></p>
<p>Curabitur blandit tempus porttitor.</p>
</article>
С помощью :empty
вы можете найти это и скрыть.
.post :empty {
display: none;
}
Поиск и исключение нескольких элементов
Некоторые псевдоклассы помогают писать более компактный CSS.
:is()
Если вы хотите найти все дочерние элементы h2
, li
и img
в элементе .post
, вы можете подумать о написании списка селекторов следующим образом:
.post h2,
.post li,
.post img {
…
}
С помощью псевдокласса :is()
можно написать более компактную версию:
.post :is(h2, li, img) {
/* ... */
}
Псевдокласс :is
не только компактнее списка селекторов, но и более терпим к ошибкам. В большинстве случаев, если в списке селекторов есть ошибка или неподдерживаемый селектор, весь список селекторов перестанет работать. Если в переданных селекторах псевдокласса :is
есть ошибка, он проигнорирует недопустимый селектор и использует допустимые.
:not()
Вы также можете исключать элементы с помощью псевдокласса :not()
. Например, его можно использовать для оформления всех ссылок, у которых нет атрибута class
.
a:not([class]) {
color: blue;
}
Псевдокласс :not
также может помочь улучшить доступность. Например, элемент <img>
должен иметь атрибут alt
, даже если это пустое значение, поэтому вы можете написать CSS-правило, которое добавляет толстую красную рамку к недопустимым изображениям:
img:not([alt]) {
outline: 10px red;
}
:has()
Что делать, если вы хотите стилизовать элементы в зависимости от их содержимого? Для этого можно использовать псевдокласс :has()
. Например, можно применить стили к кнопкам со значками.
button:has(svg) {
/* ... */
}
В самой простой конфигурации, как и в предыдущем примере, :has()
можно рассматривать как родительский селектор. Вы также можете использовать соответствующий родительский селектор в сочетании с другими селекторами для выбора других элементов.
form:has(input:valid) label {
font-weight: bold;
}
form:has(input:valid) label::after {
content: "✅";
}
В этом примере мы применяем стили к элементу label и псевдоэлементу label::after
, когда поле ввода формы имеет valid
псевдокласс.
Псевдокласс :has()
не может быть вложен в другой :has()
, но его можно комбинировать с другими псевдоклассами.
:is(h1, h2, h3):has(a) {
/* ... */
}
Список селекторов не прощает ошибок, поэтому, если какие-либо селекторы в списке недействительны, все правила стилей будут проигнорированы.
.my-element:has(img, ::before) {
/* any styles here will be discarded since pseudo elements can't be included in the :has() selector list */
}
Проверьте свое понимание
Проверьте свои знания псевдоклассов
Псевдоклассы действуют так, как если бы класс был динамически применен к элементу, в то время как псевдоэлементы действуют на сам элемент.
Какой из перечисленных ниже псевдоклассов является функциональным ?
:empty
:is()
:not()
:target
Какие из следующих псевдоклассов обусловлены взаимодействием с пользователем?
:target
:hover
:focus-within
:press
:squeeze
Какие из следующих являются псевдоклассами состояния <form>
?
:loading
:in-range
:checked
:valid
:indeterminate
:fresh
:enabled