CSS :has(): Условная стилизация родителя и соседей без JavaScript-классовДолгое время задача стилизовать родителя на основе его потомка или соседний элемент по состоянию соседа решалась только через JavaScript с ручным добавлением/удалением классов. Селектор
:has() навсегда закрывает этот пробел, позволяя описывать такие паттерны декларативно, прямо в CSS, устраняя классы-костыли и снижая риск визуальных артефактов.
Как это работает и синтаксисСелектор
:has() применяет стили к элементу, если внутри его DOM-дерева есть другой элемент, удовлетворяющий заданному условию. Классический пример — подсветка списка при наличии выполненной задачи:
ul:has(li.done) {
border: 2px solid green;
}Всё, никаких дополнительных классов на
<ul> — браузер сам проверяет вложенность. Это радикально упрощает поддержку компонентов.
Conditional соседей и респонсив:has() работает и с соседними селекторами, что открывает сценарии управления отступами или визуальной иерархией без JavaScript. Пример:
.card:has(+ .featured) {
margin-bottom: 24px;
}Здесь
margin-bottom у карточки добавляется только если сразу после неё идёт элемент с классом
featured. Это идеально для списков в e-commerce или карточек в кабинетах, где порядок определяется бекендом, а визуальные отступы должны адаптироваться.
Типичная ошибка: перегрузка сложными селекторамиСамая частая проблема — использовать
:has() для проверки глубоко вложенных условий внутри большой страницы, например:
body:has(.sidebar.open) .main {
margin-left: 300px;
}Такой селектор заставляет браузер при каждом изменении проверять всех потомков
<body>. На статичных страницах это почти незаметно, но на динамических интерфейсах с частыми ре-рендерами (лендинги с анимациями, панели управления) может дать задержку. Практический совет: ограничивай глубину проверки до 1-2 уровней и избегай зацикливания через
:has() внутри
:has() — это гарантированно сломает layout.
Production-ориентированный пример: формы и валидацияОдин из самых полезных сценариев — подсветка всей формы при невалидном поле без JS:
form:has(input:invalid) {
border: 2px solid #e53e3e;
box-shadow: 0 0 0 1px rgba(229, 62, 62, 0.3);
}Это даёт пользователю мгновенный визуальный фидбек: если в форме есть ошибка, весь её контейнер выделяется красной рамкой. Для accessibility важно не забыть aria-атрибуты на самой форме, но это уже вопрос семантики. Основное trade-off:
:has(input:invalid) работает только в современных браузерах (Safari 15.4+), поэтому для поддержки старых версий нужна progressive enhancement.
Вывод: :has() — инженерный инструмент, который делает верстку более предсказуемой, убирая лишние JS-проверки, но требует строгого контроля над глубиной вложенности и браузерной поддержкой.