В редакторском проекте Рабочей группы CSS по селекторам уровня 4 есть несколько селекторов псевдоклассов, которые уже имеют определенную поддержку в большинстве современных браузеров. В этом руководстве рассказывается о селекторах, которые в настоящее время имеют наилучшую поддержку, а также приводятся примеры, демонстрирующие, как вы можете начать использовать их!
Селекторы псевдоклассов – это такие селекторы, которые начинаются с символа двоеточия ":" и соотносятся с состоянием элемента. Они могут относиться как к элементам в дереве документа, так и с изменением их состояния, например :hover
или :checked
.
:any-link
Хотя данный псевдокласс определен в селекторах уровня 4, он уже довольно давно имеет кроссбраузерную поддержку. Псевдокласс :any-link
соотносится с якорной гиперссылкой, если у нее есть атрибут href
. При этом он является эквивалентом сразу двух псевдоклассов ссылки - :link
и :visited
. Таким образом, если вам нужно определить базовые свойства, такие как color
, независимо от статуса посещенности ссылки, то данный псевдокласс поможет уменьшить ваши стили на один селектор.
:any-link {
color: blue;
text-underline-offset: 0.05em;
}
Важным замечанием о специфичности данного селектора является то, что :any-link
имеет более высокий приоритет как селектор по отношению к селектору a
, даже если последний расположен ниже в каскадной таблице стилей, так как он имеет специфичность класса. В следующем примере ссылки будут фиолетовыми:
:any-link {
color: purple;
}
a {
color: red;
}
Таким образом, если вы будете использовать :any-link
, то вам следует помнить, что его нужно подключать к a
в качестве селектора, в тех случаях, когда они находятся в прямой конкуренции за специфичность.
:focus-visible
Одним из наиболее распространенных нарушений принципа доступности в Интернете является удаление свойства outline
у интерактивных элементов, таких как ссылки, кнопки и поля ввода форм, когда они находятся в состоянии фокуса - :focus
. При этом одной из основных задач свойства outline
- это визуальная индикация для пользователей, которые используют клавиатуру для навигации по странице. Состояние видимого фокуса имеет решающее значение в качестве инструмента поиска путей, поскольку эти пользователи переходят по элементам интерфейса, нажимая кнопку Tab. При этом это состояние помогает усилить интерактивные элементы.
Псевдокласс :focus-visible
предназначен только для того, чтобы показывать кольцо фокусировки, когда пользовательский агент с помощью эвристики определяет, что оно должно быть видимым. Другими словами, браузеры будут определять, когда применять :focus-visible
, основываясь на таких вещах, как метод ввода, тип элемента и контекст взаимодействия. При тестировании на настольном компьютере с клавиатурой и мышью вы должны увидеть заданные стили :focus-visible
, когда вы используете клавишу Tab для перехода на интерактивный элемент, но не при нажатии на него кнопкой мыши. Исключение касается только текстовых полей вводов и текстовых областей, которые должны отображать стили :focus-visible
для всех типов ввода фокуса.
Похоже, что в настоящее время последние версии браузеров Firefox и Chromium обрабатывают псевдокласс :focus-visible
для элементов ввода форм в соответствии со спецификацией, в которой говорится, что UA должен удалять стили :focus
, когда есть соответствующие стили :focus-visible
. Safari пока не поддерживает :focus-visible
, поэтому, чтобы избежать удаления свойства outline
, необходимо предоставить стили :focus
для обратной совместимости.
Возьмем кнопку и текстовое поле ввода со следующим набором стилей и давайте посмотрим, что произойдет:
input:focus,
button:focus {
outline: 2px solid blue;
outline-offset: 0.25em;
}
input:focus-visible {
outline: 2px solid transparent;
border-color: blue;
}
button:focus:not(:focus-visible) {
outline: none;
}
button:focus-visible {
outline: 2px solid transparent;
box-shadow: 0 0 0 2px #fff, 0 0 0 4px blue;
}
CHROMIUM И FIREFOX
input
Когда элемент получает фокус при помощи мыши, корректно удаляет стили
:focus
в пользу:focus-visible
, что приводит к изменению свойстваborder-color
и прячетoutline
при вводе с клавиатуры.button
Не только использует
:focus-visible
без дополнительного правила дляbutton:focus:not(:focus-visible)
, которое удаляетoutline
для:focus
, но и сделает видимымbox-shadow
только при вводе с клавиатуры.
SAFARI
input
Продолжает использовать только стили
:focus
.button
В настоящее время частично применяется
:focus-visible
, скрывая стили:focus
при нажатии кнопкой мыши, однако при использовании клавиатуры все еще применяются стили:focus
.
Таким образом на данный момент рекомендуется продолжать включать стили :focus
, а затем постепенно улучшать их до использования :focus-visible
.
:focus-within
Псевдокласс :focus-within
поддерживается всеми современными браузерами и действует почти как родительский селектор, но только для очень специфических условий. При использовании с элементом-контейнером, когда у его дочернего элемента возникает состояние фокуса, то стили могут быть добавлены к контейнеру и/или любым другим элементам в контейнере.
На практике это можно использовать, например, для определения стиля метки формы, когда форма получит фокус. Для этого нужно поместить метку и поле ввода внутри контейнера, а затем прикрепить к метке внутри контейнера :focus-within
:
.form-group:focus-within label {
color: blue;
}
В результате, когда поле ввода получит фокус, метка станет синего цвета.
:is()
Псевдокласс :is()
может принимать список селекторов для сопоставления. Например, вместо того, чтобы перечислять стили заголовков по отдельности, вы можете сгруппировать их под селектором :is(h1, h2, h3)
.
Вот несколько уникальных особенностей поведения селектора :is()
:
- Если указанный в списке селектор недействителен, правило будет по-прежнему действовать для допустимых селекторов. Например, в селекторе
:is(-ua-invalid, article, p)
правило будет действовать дляarticle
иp
. - Вычисленная специфичность будет такой же как специфичность переданного селектора с самой высокой специфичностью. Например,
:is(#id, p)
будет иметь специфичность как у#id
, т.е. 1.0.0, в то время как:is(p, a)
будет иметь специфичность 0.0.1.
Первая особенность, касающаяся игнорирования недействительных селекторов, это ключевое достоинство этого псевдокласса. При обычном использовании других селекторов в группе, где один селектор недействителен, браузер отбросит все правило. Это начинает действовать в тех случаях, когда браузерные префиксы все еще необходимы, а группировка селекторов с префиксами и без префиксов приводит к сбою правила во всех браузерах. С псевдоклассом :is()
можно безопасно группировать такие стили, и они будут применяться, когда они совпадают, и игнорироваться, когда не совпадают.
:is(h1, h2, h3) {
line-height: 1.2;
}
:is(h2, h3):not(:first-child) {
margin-top: 2em;
}
В приведенном примере наличие большего line-height
, унаследованного от базовых стилей, или отсутствие margin-top
на самом деле не будет проблемой для не поддерживающих браузеров. Для чего не стоит использовать псевдокласс :is()
- это критические стили для создания компоновки страницы, такие как сетка, которые в значительной степени отвечают за интерфейс сайта.
Кроме того, при подключении к другому селектору вы можете проверять, совпадает ли базовый селектор с селектором-потомком внутри псевдокласса :is()
. Например, следующее правило выбирает только те абзацы, которые являются прямыми потомками статей. Универсальный селектор используется в качестве ссылки на базовый селектор p
.
p:is(article > *)
Для лучшей текущей поддержки, если вы хотите начать использовать данный псевдокласс, вам также потребуется удвоить количество стилей, включив дублирующие правила с использованием :-webkit-any()
и :matches()
. Не забудьте определить эти отдельные правила, иначе даже поддерживающие браузеры отбросят заданные стили! Другими словами, не забывайте определять все три правила:
:matches(h1, h2, h3) { }
:-webkit-any(h1, h2, h3) { }
:is(h1, h2, h3) { }
Стоит сказать, что наряду с самими новыми селекторами есть еще и обновленная версия правила @supports
, которая имеет вид @supports селектор
. Также, есть вариант @supports not селектор
.
Примечание: В настоящее время (из современных браузеров) только Safari не поддерживает данное @-правило.
Вы можете проверить наличие поддержки псевдокласса :is()
следующим образом, но при этом вы потеряете поддержку в Safari, поскольку Safari поддерживает :is()
, но не поддерживает @supports селектор
:
@supports selector(:is(h1)) {
:is(h1, h2, h3) {
line-height: 1.1;
}
}
:where()
Псевдокласс :where()
почти идентичен псевдоклассу :is()
за исключением одного важного отличия: он всегда имеет нулевую специфичность. Это открывает невероятные возможности для разработчиков различных фреймворков, тем и систем проектирования. Используя :where()
, разработчик системы или темы может устанавливать значения по умолчанию, а последующие разработчики могут включать переопределения или расширения без конфликтов специфичности.
Рассмотрим следующий набор стилей для селектора img
. При использовании :where()
, даже с селектором более высокой специфичности, специфичность остается нулевой. В следующем примере, как вы думаете, какого цвета будет рамка у изображения?
:where(article img:not(:first-child)) {
border: 5px solid red;
}
:where(article) img {
border: 5px solid green;
}
img {
border: 5px solid orange;
}
Первое правило имеет нулевую специфичность, поскольку оно полностью находится внутри псевдокласса :where()
. Таким образом, в сравнении со вторым правилом побеждает второе правило. Добавленный селектор-элемент img
в качестве последнего стиля в соответствии с правилами каскада получает главный приоритет. Это связано с тем, что у него такая же специфичность как и у правила :where(article) img
, поскольку часть с псевдоклассом :where()
никак не увеличивает специфичность.
Использование :where()
наряду со стилями для обратной совместимости вызывает некоторые трудности из-за особенности нулевой специфичности, так как эта особенность, вероятно, может сталь главной причиной, по которой вы захотите отдать предпочтение этому псевдоклассу вместо псевдокласса :is()
. И если вы добавите стили, предназначенные для обратной совместимости, они, скорее всего, победят стили с псевдоклассом :where()
в силу природы последнего. При этом у него лучшая общая поддержка, чем у @supports селектор
, таким образом, попытка использовать его для создания стилей обратной совместимости вряд ли даст большую (если вообще даст) выгоду. В принципе, для эффективного использования данного псевдокласса достаточно осознавать невозможность правильного создания стилей для обратной совместимости с :where()
и тщательно проверять свои собственные данные, чтобы определить безопасно ли начинать использовать их для вашей уникальной аудитории.
Улучшенный :not()
Базовые свойства селектора :not()
поддерживаются начиная с Internet Explorer 9. Но Селекторы 4-го уровня улучшают :not()
, позволяя ему принимать список селекторов, точно так же, как :is()
и :where()
.
Следующие правила дадут одинаковые результаты в поддерживаемых браузерах:
article :not(h2):not(h3):not(h4) {
margin-bottom: 1.5em;
}
article :not(h2, h3, h4) {
margin-bottom: 1.5em;
}
Способность псевдокласс :not()
принимать список селекторов хорошо поддерживается современными браузерами.
Как и в случае с :is()
, улучшенный :not()
также может принимать ссылку на базовый селектор в качестве последующего использования *
.
:empty
И в заключение стоит упомянуть полезный псевдокласс из предыдущей спецификации Селекторов уровня 3, который вы, возможно, пропустили - :empty
. Данный псевдокласс соответствует элементу, у которого нет дочерних элементов, включая текстовые узлы.
Так, правило p:empty
будет соответствовать элементу <p></p>
, но не <p>Привет</p>
.
Один из способов, как вы можете использовать псевдокласс :empty
, - это скрыть элементы, которые являются заглушками для динамического содержимого, предоставляемого при помощи JavaScript. Например, у вас есть div
, который будет получать результаты поиска, и когда он будет заполнен, у него будет рамка и некоторые отступы. Но пока результатов нет, вы не хотите, чтобы он занимал место на странице. При помощи :empty
вы можете его скрыть:
.search-results:empty {
display: none;
}
Возможно, вы подумывали о том, чтобы добавить сообщение в элемент в пустом состоянии, и у вас возникает соблазн добавить его с помощью этого псевдоэлемента и свойства content
. Но здесь есть один подводный камень, который заключается в том, что пользователям вспомогательных технологий могут быть недоступны сообщения в свойстве content
. Другими словами, чтобы сообщение типа "нет результатов" было доступно, вам стоит добавить его в качестве реального элемента, такого как абзац (aria-label
не доступен для скрытого div
).