Подкаст 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 */
}
Проверьте свое понимание
Проверьте свои знания псевдоклассов
Псевдоклассы действуют так, как если бы класс был динамически применен к элементу, в то время как псевдоэлементы действуют на сам элемент.
: в качестве ключевого отличительного символа в селекторе.Какой из перечисленных ниже псевдоклассов является функциональным ?
:is():target() , которые указывают на то, что они принимают параметры.:empty() , которые указывают на то, что они принимают параметры.:not()Какие из следующих псевдоклассов обусловлены взаимодействием с пользователем?
:hover:press:squeeze:target:focus-within Какие из следующих являются псевдоклассами состояния <form> ?
:enabled:fresh:indeterminate:checked:in-range:loading:valid