CSS - :has()
Псевдокласс :has() открывает возможности для стилизации и позволяет создавать сложные и точные селекторы, делает CSS более мощным и гибким инструментом для вёрстки, предлагаем описание и демо примеры.Подробнее о псевдоклассе :has()
Псевдокласс :has() - это новый мощный селектор из спецификации CSS Selectors Level 4, который позволяет выбирать элементы на основе их содержимого или состояния потомков. Это первый "родительский селектор" в CSS, который открывает множество новых возможностей.
Основные задачи, решаемые псевдоклассом :has(), связаны с повышением гибкости оформления элементов относительно их содержимого, управлением поведением интерфейса и адаптацией дизайнов под разные сценарии использования. Это значительно расширяет выразительные возможности CSS и улучшает опыт разработчика, делая процесс проектирования и реализации интерфейсов проще и эффективнее.
Применение псевдокласса :has() существенно упрощает работу с адаптивными интерфейсами и повышает удобство дизайна, предоставляя возможность выбора элементов исходя из их внутренней структуры. Несмотря на частичную поддержку браузерами, он представляет собой перспективную технологию, заслуживающую внимания разработчиков современных веб-приложений.
Пока полная поддержка :has() не стала повсеместной, разработчики чаще всего прибегают к JavaScript решениям или комбинируют методы для достижения нужного эффекта. Тем не менее, развитие стандарта CSS делает возможным появление полноценного механизма выборки элементов на основе структуры дерева DOM в будущем.
Поддержка браузеров псевдокласса :has()
При открытии этой страницы ваш браузер проходит автоматическую проверку на поддержку псевдокласса :has() с демонстрацией уведомления в правом нижнем углу.
Вы можете открыть наш материал в разных браузерах которые установлены на всех ваших устройствах, чтобы проверить их актуальность поддержки псевдокласса :has().
Таблица поддержки браузеров псевдокласса :has()
| Браузер | Поддержка | Версия | Дата выхода | Примечания |
|---|---|---|---|---|
| Chrome | Полная | 105+ | Август 2022 | Стабильная поддержка |
| Полная | 105+ | Август 2022 | На движке Chromium | |
| Safari | Полная | 15.4+ | Март 2022 | Начиная с Safari 15.4 (macOS 12.3+) |
| Firefox | Полная | 121+ | Декабрь 2023 | Долгожданная поддержка |
| Edge | Полная | 105+ | Август 2022 | На движке Chromium |
| Opera | Полная | 91+ | Сентябрь 2022 | На движке Chromium |
| Internet Explorer | Нет | - | - | Не поддерживается |
| iOS Safari | Полная | 15.4+ | Март 2022 | Только новые устройства |
| Android Browser | Частичная | 105+ | 2022 | Зависит от версии WebView |
Аналоги использования :has()
Хочется сразу обратить ваше внимание на способы альтернативной замены использования псевдокласса :has(), примеры самые распространённые и добавлены "чтобы было".
Использование JavaScript
Самый надежный способ - проверить наличие нужных элементов средствами JavaScript и применить стили динамически:
document.querySelectorAll('.parent').forEach(parent => {
if (parent.querySelector('child')) {
parent.classList.add('has-child');
}
});
Затем можно задать стили через этот дополнительный класс:
.parent.has-child {
/* Стили */
}
Использование комбинации псевдоэлемента
Можно имитировать поведение :has() с помощью комбинаций различных техник CSS, используя вложенность и генерируемый контент:
<div class="box">
<img src="..." alt="Image"/>
</div>
<div class="box"></div>
Чтобы выбрать первый блок, содержащий картинку, можно использовать следующий трюк:
.box img + ::after {
content: '';
display: block;
height: 0;
width: 0;
}
.box::after {
content: 'contains image';
visibility: hidden;
}
.box:not(:empty)::after {
visibility: visible;
}
Хотя этот метод довольно сложный и менее читаемый, он позволяет достичь похожего результата, особенно в простых случаях.
Использование атрибутов данных
Используя серверную сторону или JavaScript, можно добавлять специальные атрибуты данным элементам, позволяя легко управлять ими в CSS:
<div data-has-content="true">
<!-- Содержимое -->
</div>
<div></div>
[data-has-content='true'] {
/* Применяем нужные стили */
}
Это решение удобно тем, что оно поддерживает чистый CSS и хорошо интегрируется с любыми технологиями рендеринга страниц.
Примеры синтаксиса :has()
Псевдокласс :has() работает как функциональный селектор и принимает в качестве аргумента один или несколько селекторов, которые уточняют условие выбора элемента на основе наличия внутри него или рядом с ним указанных элементов. Вот основные варианты и особенности синтаксиса для работы с :has().
Особенности синтаксиса :has()
Основной синтаксис :has()
selector - родительский элемент, на который применяется правило. subSelector - внутренний селектор, определяющий наличие конкретного потомка или условия:
selector:has(subSelector) { правила стиля }
Использование комбинаторов внутри :has()
> - выбирает прямых потомков и применит стиль только к <div>, у которого есть именно прямой дочерний <img>:
div:has(> img) { правила стиля }
+ - выбирает следующий соседний элемент и стилизует <h2>, если сразу после него идёт <p>:
h2:has(+ p) { правила стиля }
~ - выбирает любой следующий соседний элемент на одном уровне вложенности, не обязательно сразу следующий:
div:has(~ img) { правила стиля }
Пробел между селекторами - выбирает всех потомков независимо от уровня вложенности и стилизует <article>, если внутри есть <figure>, а внутри <figure> - <img>:
article:has(figure img) { правила стиля }
Несколько селекторов через запятую в :has()
Можно передавать несколько селекторов через запятую. В этом случае стиль применяется, если выполняется хотя бы одно из условий:
div:has(.class1, #id2) { правила стиля }
Комбинация нескольких :has() подряд
Чтобы уточнить условие, можно составлять цепочки, это выберет <div>, содержащие <img> и элементы с классом .highlight:
div:has(img):has(.highlight) { правила стиля }
Ограничения
- Нельзя вкладывать
:has()внутрь самого себя, то есть не:has(:has(...)), это запрещено из-за потенциальных циклических запросов. - В аргументах
:has()нельзя использовать псевдоэлементы (например,::beforeили::after). - Нельзя использовать
:has()внутри:not().
Можно использовать сложные селекторы, включая псевдоклассы для уточнения условий, например:
form:has(input:invalid) { правила стиля }
:has(:not(p)) { правила стиля }
Вложенные :has() допустимы, но сложны для чтения:
div:has(> section:has(h2)) { правила стиля }
Варианты синтаксиса :has()
Простой селектор по классу
Выбрать элемент, содержащий дочерний элемент с классом:
.parent:has(.child) {
border: 1px solid #ddd;
}
Селектор по типу элемента
Выбрать <div>, содержащий параграф:
div:has(p) {
padding: 15px;
}
Селектор с атрибутом
Выбрать элемент, содержащий ссылку с атрибутом target="_blank":
section:has(a[target="_blank"]) {
background-color: #f9f9f9;
}
Комбинация с :hover
Выбрать элемент, если внутри есть наведенный элемент:
.menu:has(li:hover) {
box-shadow: 0 0 5px rgba(0,0,0,0.2);
}
Проверка на несколько элементов
Выбрать элемент, если внутри есть и <h2> и <p>:
article:has(h2):has(p) {
margin-bottom: 30px;
}
Селектор по псевдоклассу состояния
Выбрать форму, содержащую невалидное поле:
.form-group:has(input:invalid) {
color: #a94442;
}
Комбинация с :checked
Выбрать <div>, содержащий отмеченный чекбокс:
div:has(input[type="checkbox"]:checked) {
background-color: #dff0d8;
}
Селектор по порядку элементов
Выбрать список, если в нем больше 5 элементов:
ul:has(li:nth-child(5)) {
column-count: 2;
}
Комбинация с :empty
Выбрать элемент, если он содержит пустой дочерний элемент:
.container:has(.alert:empty) {
display: none;
}
Селектор по соседнему элементу
Выбрать <h2>, если сразу после него идет <p>:
h2:has(+ p) {
margin-bottom: 5px;
}
Комбинация с :first-child
Выбрать элемент, если первый дочерний <span>:
div:has(> :first-child span) {
padding-left: 0;
}
Селектор по data атрибуту
Выбрать элемент, содержащий кнопку с data-toggle="modal":
.card:has([data-toggle="modal"]) {
cursor: pointer;
}
Комбинация с классами Bootstrap
Выбрать элемент, содержащий кнопку .btn-primary:
.panel:has(.btn-primary) {
border-color: #337ab7; /* Цвет primary из Bootstrap */
}
Проверка на отсутствие элемента
Выбрать элемент, если в нем нет .error (через :not):
form:not(:has(.has-error)) .submit-btn {
background-color: #5cb85c; /* Цвет success из Bootstrap */
}
Комбинация с :focus
Выбрать .input-group, если внутри есть поле в фокусе:
.input-group:has(input:focus) {
box-shadow: 0 0 8px rgba(102,175,233,.6); /* Как в Bootstrap */
}
Селектор по количеству элементов
Выбрать таблицу, если в ней больше 10 строк:
.table:has(> tbody > tr:nth-child(10)) {
font-size: 13px;
}
Комбинация с :disabled
Выбрать <fieldset>, если все дочерние инпуты отключены:
fieldset:has(> :not(legend):disabled:last-child) {
opacity: 0.6;
}
Селектор по вложенности
Выбрать .modal, если внутри есть .modal-footer:
.modal:has(.modal-footer) .modal-body {
padding-bottom: 0;
}
Комбинация с :valid/:invalid
Выбрать .form-group, если есть валидное поле и нет невалидных:
.form-group:has(input:valid):not(:has(input:invalid)) {
border-left: 3px solid #5cb85c; /* Цвет success из Bootstrap */
}
Сложный составной селектор
Выбрать .panel, если внутри есть .btn-danger или .alert-danger:
.panel:has(.btn-danger, .alert-danger) {
border-color: #d9534f; /* Цвет danger из Bootstrap */
}
Практические примеры с :has()
Подробные демо примеры готового кода, для использования псевдокласса :has(). Примеры демонстрируют, как :has() может значительно упростить логику стилизации, заменяя JavaScript для многих сценариев. Код в редакторе можно не только воспроизводить, но и пробовать редактировать, чтобы лучше понять как работает сценарий с псевдоклассом :has().
Работа со списками
Стилизация списка с выделенным элементом. Голубая рамка появляется только у списков, содержащих элемент с классом .active:
Многоуровневые списки. Родительский пункт становится жирным, если любой из его потомков имеет класс .expanded:
Работа с таблицами
Выделение строки с чекбоксом. Строка с активным чекбоксом подсвечивается, а таблица получает рамку если есть хотя бы один отмеченный чекбокс:
Сложные условия в таблице. Таблица получает предупреждение, если содержит ячейки с классом .low-stock:
Работа с формами
Валидация полей. Группа полей меняет цвет в зависимости от валидности ввода (пароль минимум 4 символа):
Динамические формы. Опции темы показываются только при включённом тёмном режиме:
Комбинированные примеры
Карточки товаров. Карточки с акцией получают особое оформление:
Адаптивный контейнер. Блоки контента адаптируются в зависимости от количества и размера изображений:
Сложные комбинации
Интерактивная галерея. Селектор .gallery:has(.thumbnails .active) применяет стили ко всему блоку с классом .gallery, но только при условии, что внутри него есть элемент с классами .thumbnails .active:
Проверка браузера на поддержку :has()
Сделайте проверку вашего браузера на поддержку псевдокласса :has(). Напоминаем, что проверка поддержки осуществляется автоматически, при загрузке страницы.







