Ванильный код
March 24, 2022

Объединение селекторов в цепочку с помощью :is

Обычная задача в CSS - применить некоторый стиль к нескольким селекторам. Было бы неплохо, если бы мы могли сократить количество повторений селекторов и указать основной только один раз. И оказывается, что мы можем!

Предположим, вы хотите применить тот же стиль к состояниям фокуса, наведения и какому-то значению атрибут элемента, например, для навигационной ссылки:

.nav-link:focus,
.nav-link:hover,
.nav-link[aria-current="page"] {}

Для каждого нового селектора вам необходимо повторить базовый селектор (.nav-link).

Хотя в этом изолированном примере это может показаться несущественным, но чем больше специфики верстки, тем больше приходится писать CSS подобным образом. Кстати, стили еще разрастутся, если вам нужно использовать дополнительные модификаторы, например, с помощью :not:

.button:not(.disabled):focus,
.button:not(.disabled):hover {}

Если вы используете Sass, то можете сказать, что там не все так плохо благодаря использованию амперсанда:

.nav-link {
  &:focus,
  &:hover,
  &[aria-current="page"] {}
}

Но спешу вас расстроить, вы все равно в конечном итоге отправляете тот же объем выходного CSS.

Было бы неплохо, если бы мы могли сократить количество повторений и указать основной селектор только один раз. И оказывается, что мы можем!


Все основные браузеры теперь поддерживают функцию псевдокласса :is.

Он принимает список селекторов, разделенных запятыми, для сопоставления, что позволяет вам писать меньше строк CSS для выполнения той же задачи, что и раньше.

Вот как выглядел бы наш предыдущий пример, если бы мы использовали :is:

.nav-link:is(:focus, :hover, [aria-current="page"]) {}

Этот селектор будет соответствовать всем элементам с классом nav-link, которые также имеют псевдокласс :focus, псевдокласс :hover или атрибут aria-current="page". Это позволяет вам объединить все ваши стили для элемента в одном селекторе.

Мы также можем провести рефакторинг второго примера, где мы связали дополнительные модификаторы с помощью :not:

.button:not(.disabled):is(:focus, :hover) {}

Это здорово, потому что это означает, что нам не нужно повторять какие-либо промежуточные классы или псевдоклассы — нам нужно только перечислить их один раз и связать в цепочку :is, чтобы предоставить дополнительный список селекторов.

Функция псевдокласса :is еще приятнее в Sass, поскольку вам вообще не нужно повторно вводить базовый селектор и вы можете просто использовать оператор амперсанда:

.nav-link {
  /* основные стили */

  &:is(:focus, :hover, [aria-current="page"]) {
    /* стили активных состояний */
  }
}

Наконец, стоит отметить, что, хотя во всех примерах до сих пор рассматривалась цепочка :is с базовым селектором, на самом деле вы можете просто использовать :is самостоятельно. Например, в следующем CSS :is используется для получения прямых потомков определенных родительских селекторов:

:is(.parent1, .parent2, .parent3) > * {}

Без использования :is пришлось бы написать вот так:

.parent1 > *,
.parent2 > *,
.parent3 > * {}

Важные моменты

Специфичность (вес)

Во-первых , :is получает самую большую специфичность из своего списка аргументов.

Это означает, что он идеально подходит для ситуаций, когда все селекторы, которые вы перечисляете, имеют одинаковую специфику. Так обстоит дело в первом примере, который мы видели, где все селекторы имеют общую специфику класса:

.nav-link:is(:focus, :hover, [aria-current="page"]) {}

Но в следующем примере общая специфичность :is оказывается выше из-за наличия id в первом списке селекторов, поэтому будущие селекторы с более низкой специфичностью будут переопределены:

<div class="class"></div>
div:is(#id, .class) {
  background: red;
}

/* Всегда будет переопределено */
div:is(.class, .another-class) {
  background: blue;
}

В этом примере div в конечном итоге имеет красный цвет фона, а не синий, потому что id в первом селекторе увеличивает общую специфичность селектора.

Прощающий синтаксический анализ селектора

Во-вторых, :is использует прощающий синтаксический анализ селектора, что означает, что если один из перечисленных вами селекторов окажется недействительным, весь список аргументов не будет признан недействительным. Вот пример:

.element:is(:focus, :unrecognized-selector) {}

:is по-прежнему будет анализировать список аргументов и применять стиль к элементу, если встречается допустимый селектор (в данном случае :focus).

На этом статья подходит к концу, надеюсь вы узнали для себя что-то новое!

Если вам хочется почитать и другие стать из рубрики #научите_меня_css, то не забывайте подписываться на мой телеграм канал и искать там по этому хештегу!

Читать еще: