:has() в продакшене: три сценария, которые меняют подход к CSS
:has() в продакшене: три сценария, которые меняют подход к CSS CSS-селектор :has() наконец-то стабилен в браузерах и реально востребован в современных интерфейсах. Он позволяет стилизовать родителя по состоянию потомка, что раньше требовало JavaScript или костылей с классами. Частая ошибка — использовать его везде, не оценивая производительность и поддержку. 1. State-селекторы без JS Раньше, чтобы подсветить карточку при наведении на кнопку внутри, приходилось лепить JS-обработчики. Сейчас можно одной строкой: .card:has(.action-btn:hover) { box-shadow: 0 0 0 2px var(--accent); transform: scale(1.02); } Работает с :focus-within, :checked и любыми псевдоклассами. Полезно для интерактивных списков, где нужно визуально выделять активный элемент без мутаций DOM. 2. Form-validation UX без классов Типичная задача: инпут с ошибкой, сообщение об ошибке под ним. Раньше через JS вешали класс на родителя. Теперь: .field:has(+ .error-msg:not(:empty)) input { border-color: var(--error); } Условие читается как "если после поля есть блок с ошибкой и он не пустой — крась рамку в красный". Всё реактивно, стили обновляются автоматически. Это упрощает код и устраняет задержки на установку классов. 3. Адаптивные layout’ы без медиавыражений Вместо ширины экрана смотрим на содержимое. Например, если карточек меньше трёх — оставляем одну колонку, три и больше — две: .grid:has(.card:nth-child(3)) { grid-template-columns: repeat(2, 1fr); } Или сайдбар пустой — контент на всю ширину: .layout:has(.sidebar:empty) .content { grid-column: 1 / -1; } Для простых кейсов заменяет @container, но без поддержки контекста размера. Подходит для вложенных списков или вариативных форм. Trade-offs и предупреждение :has() — дорогой селектор. На списках из тысяч элементов с частыми перерисовками (например, drag-and-drop или live-обновления) он может тормозить. Всегда тестируй производительность в DevTools Performance. Поддержка ~92% глобально. Если нужен fallback для старых браузеров — оставляй JS-классы как запасной вариант. Вывод: :has() переносит часть UI-логики из JS в CSS, но используй его осознанно: только для статичных или редко изменяющихся структур, иначе рискуешь получить фреймовую задержку.