CSS-псевдокласс :is() — инструмент для группировки селекторов. Вместо того чтобы дублировать одно и то же правило для каждого тега отдельно, вы перечисляете нужные элементы через запятую внутри :is() , и браузер применяет стиль к каждому из них. В этой статье разберём синтаксис селектора :is() , покажем, где он экономит больше всего кода, и объясним единственный нюанс, который стоит знать.
Что такое псевдокласс :is() в CSS
:is() — CSS-псевдокласс из спецификации Selectors Level 4. Работает просто: в скобках пишете теги, классы или любые другие селекторы — браузер применяет стиль к каждому из них.
Посмотрите на два одинаковых по результату правила:
/* Обычный способ */
h1, h2, h3 {
line-height: 1.3;
}
/* Через псевдокласс :is() */
:is(h1, h2, h3) {
line-height: 1.3;
} На таком простом примере разницы нет. Настоящая польза от :is() начинается, когда нужно стилизовать элементы внутри нескольких родителей — разберём это подробнее.
Зачем нужен селектор :is() — задача без него
Допустим, нужно стилизовать все ссылки внутри article , section и aside . Без :is() это три строки с одинаковым правилом:
article a,
section a,
aside a {
text-decoration: underline;
} С :is() — одна:
:is(article, section, aside) a {
text-decoration: underline;
} Чем больше родительских элементов и чем разнообразнее дочерние — тем сильнее выигрыш.
:is() с несколькими уровнями — где экономия максимальна
Если нужно охватить сразу несколько родителей и несколько дочерних элементов, CSS без :is() разрастается быстро. Три родителя, три заголовка — уже девять строк. Добавьте все шесть уровней h1–h6 — получите восемнадцать. С :is() это одна строка независимо от количества:
:is(article, section, aside) :is(h1, h2, h3, h4, h5, h6) {
font-weight: bold;
} Браузер сам раскрывает это правило во все восемнадцать комбинаций. Добавить main в список родителей — дописать одно слово.
Другой типичный сценарий — интерактивные состояния ссылок:
/* Было */
nav a:hover,
nav a:focus,
nav a:active {
color: blue;
}
/* Стало */
nav a:is(:hover, :focus, :active) {
color: blue;
} Один нюанс: не мешайте классы и теги в одном :is()
В CSS классы ( .active ) «весомее» тегов ( p , span ) — они перебивают стили тегов при конфликте. Если положить классы и теги в один :is() вместе, всё правило получает вес класса — в том числе для тегов внутри. Это может неожиданно перебить ваши другие стили.
/* Проблема: p внутри :is() ведёт себя как класс,
а значит перебьёт обычное правило для p */
:is(.active, p) { color: red; }
p { color: black; } /* этот стиль проиграет! */
/* Безопасно: держим классы и теги отдельно */
.active { color: red; }
p { color: black; } Простое правило: если внутри :is() только теги — всё в порядке. Только классы — тоже. Мешать их в одном :is() стоит осознанно.
:is() и :not() — включение и исключение
:not() — обратная сторона медали: применить стили ко всему, кроме перечисленных элементов. Вместе они читаются почти как обычная речь.
Например, подчёркивать все ссылки в статье, кроме тех, что уже стилизованы как кнопки:
:is(article, section, aside) a:not(.btn) {
text-decoration: underline;
} С 2022 года :not() тоже принимает список через запятую — так что это полностью симметричная пара.
:is() против :where() — в чём разница
Есть псевдокласс-близнец — :where() . Синтаксис у него точно такой же, как у :is() , но он намеренно сделан «невесомым»: его стили проигрывают любому другому правилу для того же элемента.
Представьте, что вы пишете стили для блога и хотите задать дефолтный отступ под абзацами. Но при этом хотите, чтобы в любом конкретном месте это легко можно было переопределить:
/* :where() — «мягкий» стиль, его легко перебить */
:where(article, section) p {
margin-bottom: 1rem;
}
/* Этот стиль победит, даже если он написан выше */
.intro p {
margin-bottom: 0;
} С :is() так не получится — его стиль имеет нормальный вес и будет конкурировать с остальными правилами. Для большинства задач подходит :is() , а :where() пригодится, когда нужны стили «по умолчанию», которые никому не мешают.
Практические примеры
Состояния полей формы. Несколько состояний сразу, без повторений:
input:is(:focus, :focus-visible) {
outline: 2px solid blue;
border-color: blue;
}
:is(input, textarea, select):is(:invalid, .is-error) {
border-color: red;
} Типографика в контенте. Единые отступы для всех текстовых блоков:
.content :is(p, ul, ol, blockquote, pre) {
margin-bottom: 1.5rem;
}
.content :is(h2, h3, h4) {
margin-top: 2.5rem;
margin-bottom: 1rem;
} Тёмная тема. Переключение цветов одним блоком:
[data-theme="dark"] :is(h1, h2, h3, p, li) {
color: #f0f0f0;
}
[data-theme="dark"] a:is(:hover, :focus) {
color: #93c5fd;
} Поддержка браузерами
Сейчас CSS-селектор :is() поддерживается во всех современных браузерах без исключений:
- Chrome — с версии 88 (январь 2021)
- Firefox — с версии 78 (июнь 2020)
- Safari — с версии 14 (сентябрь 2020)
- Edge — с версии 88 (январь 2021)
По данным Can I Use поддержка составляет более 96% пользователей. Старые фоллбеки через :-webkit-any() и :matches() — это история, забудьте о них.
IE 11 :is() не поддерживает. Если вы до сих пор его поддерживаете — это отдельная история, и сочувствую.
:is() — простой инструмент, который сразу делает CSS чище и короче. Найдите в своём проекте длинный список одинаковых селекторов и замените — сами удивитесь, насколько лаконичнее станет код.