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()
. Напоминаем, что проверка поддержки осуществляется автоматически, при загрузке страницы.