Селекторы :is, :where и :has
Play ITЗагрузка интерактивного демо…
Перед чтением: Операторы — общие понятия оператора, операнда и приоритетов; в CSS роль "операций" выполняют селекторы и комбинаторы.
Псевдоклассы CSS - состояния без лишней разметки
Длинные списки селекторов через запятую трудно читать и сопровождать. :is() и :where() объединяют варианты в одну запись. :has() выбирает элемент по содержимому — "родитель, внутри которого есть …" — без классов, которые раньше добавлял только JavaScript.
Базовые псевдоклассы — в псевдоклассах и псевдоэлементах. Общий обзор функций в CSS (значения и селекторы) — Функции в CSS; справочник — справочник по CSS.
Атрибутные селекторы
Атрибут в HTML — пара «имя="значение"» на теге: type="text", href="…", disabled, data-status="draft". Справочник по атрибутам — HTML, основные теги.
Атрибутный селектор в CSS выбирает элементы по такому признаку. Вес селектора [type="text"] такой же, как у класса .field — одна «десятка» в специфичности.
Точное совпадение и наличие атрибута
/* value атрибута ровно "text" */
[type="text"] {
border: 1px solid #ccc;
}
/* любой <a>, у которого href начинается с https:// */
a[href^="https://"] {
color: #2563eb;
}
/* элемент с атрибутом disabled (значение не важно) */
[disabled] {
opacity: 0.5;
cursor: not-allowed;
}
Частичное совпадение значения
Когда в классе или data-* есть общий префикс или суффикс, удобны операторы в квадратных скобках:
| Запись | Что проверяет | Пример |
|---|---|---|
[attr^="текст"] | значение начинается с текст | [class^="btn-"] — все классы вида btn-primary, btn-ghost |
[attr$="текст"] | значение заканчивается на текст | [class$="-primary"] — вариант с суффиксом -primary |
[attr*="текст"] | значение содержит подстроку текст | [class*="icon"] — класс с фрагментом icon |
[attr|="код"] | код или код-… (часто для lang) | [lang|="ru"] — ru, ru-RU |
data-* — пользовательские атрибуты для разметки без лишних классов. Пример: data-state="open" и селектор [data-state="open"].
[class^="btn-"] {
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
}
[class*="icon"] {
display: inline-block;
width: 1.25rem;
height: 1.25rem;
background-repeat: no-repeat;
background-size: contain;
}
[class$="-primary"] {
background: var(--brand, #2563eb);
color: #fff;
}
Сочетание с другими селекторами
Несколько условий в одном селекторе сужают выбор:
input[type="text"][required]— обязательное текстовое поле;a[href^="mailto:"]:hover— почтовая ссылка при наведении;form:has([type="checkbox"]:checked)— форма, где отмечен чекбокс (см. раздел:has()).
Селекторы по [class*="…"] на всей странице сложнее читать в DevTools и чуть тяжелее для пересчёта стилей. В продакшене обычно заводят явный класс .btn или имя по BEM — методологии в §111.
:is() — группировка с учётом специфичности
/* было */
article h1,
section h1,
aside h1 {
font-size: 1.5rem;
}
/* стало */
:is(article, section, aside) h1 {
font-size: 1.5rem;
}
Специфичность :is() равна самому "тяжёлому" селектору в списке. Если внутри есть #id, весь :is(...) станет таким же специфичным.
:is(#nav, .menu) a { color: blue; }
/* специфичность как у #nav — (1,0,1) */
Поддерживает вложенность и сложные селекторы:
:is(.card, .panel):is(:hover, :focus-within) {
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
:where() — та же запись, специфичность ноль
Синтаксис как у :is(), но вклад в специфичность не считается (как 0,0,0).
:where(article, section, aside) h1 {
font-size: 1.5rem;
}
Удобно для базовых стилей в дизайн-системе: их проще перебить классом компонента без гонки с #id.
:where(.btn, button[type="submit"]) {
padding: 0.5rem 1rem;
border-radius: 6px;
}
.btn--primary {
background: #2563eb;
color: #fff;
}
:is() | :where() | |
|---|---|---|
| Краткая запись | да | да |
| Специфичность | от самого сильного аргумента | 0 |
| Когда | нужна "нормальная" сила | сброс / слой базовых правил |
:has() — родитель по потомку
Код ITЗагрузка примера кода…
С :not():
.nav:has(.nav__item:not(:last-child)) {
gap: 1rem;
}
Осторожно с производительностью: :has() на больших DOM-деревьях без узкого контекста может замедлить пересчёт стилей. Ограничивайте область (.list:has(.item--active) вместо body:has(...)).
Поддержка в актуальных браузерах широкая; для старых — запасной класс из JS.
Замена "селектор-листа мечты"
Раньше невозможно было выразить "label, за которым следует input" одним правилом без :has:
label:has(+ input:focus-visible) {
color: #2563eb;
}
Связка с валидацией форм и :user-invalid в псевдоклассах.
Краткий итог
- Атрибутные селекторы — стили по
type,href,data-*и по фрагменту значения (^=,$=,*=); :is()— короткая запись нескольких селекторов, специфичность от самого «тяжёлого» аргумента;:where()— та же запись, но без добавления веса (удобно для базового слоя);:has()— стиль родителя или соседа в зависимости от содержимого внутри.
Функции значений (calc(), var(), color-mix()) — в Функции в CSS. Таблицы свойств — справочник.