В CSS долгое время отсутствовал способ прямого выбора родительского элемента на основе его дочерних элементов. Это был один из самых востребованных запросов разработчиков на протяжении многих лет. Селектор :has() , теперь поддерживаемый всеми основными браузерами, решает эту проблему. До появления :has() ` часто приходилось использовать длинные цепочки селекторов или добавлять классы для хуков стилизации. Теперь же можно стилизовать элемент на основе его взаимосвязи с потомками. Подробнее о селекторе :has() читайте в статьях «CSS Wrapped 2023» и «5 фрагментов CSS, которые должен знать каждый фронтенд-разработчик» .
Хотя этот селектор кажется небольшим, он может обеспечить огромное количество вариантов использования. В этой статье показаны некоторые примеры применения селектора :has() , которые открыли для себя компании электронной коммерции.
Ознакомьтесь с полной серией статей, частью которой является эта статья, в которой обсуждается, как компании, занимающиеся электронной коммерцией, улучшили свои веб-сайты, используя новые функции CSS и пользовательского интерфейса.
Полибазар
Благодаря селектору
:has()нам удалось отказаться от проверки выбора пользователя с помощью JavaScript и заменить её решением на основе CSS, которое безупречно работает и обеспечивает тот же пользовательский опыт, что и раньше. — Аман Сони , технический руководитель, Policybazaar
Команда Policybazaar по инвестициям巧妙地 использовала селектор :has() для наглядного визуального отображения различий между тарифными планами. На следующем изображении показаны два типа планов в интерфейсе сравнения (жёлтый и синий). Каждый план можно сравнивать только со своим собственным типом. Благодаря использованию :has() , при выборе пользователем одного типа плана, другой тип плана становится недоступным для выбора.
:has() для стилизации родительского элемента и его дочерних элементов с целью создания функциональности выбора, привязанной к категории. Код
:has() предоставляет доступ к стилю родительских элементов и их дочерних элементов. Следующий код проверяет, имеет ли родительский контейнер класс ` .disabled-group . Если да, карточка становится неактивной (серой), а кнопка «Добавить» не реагирует на щелчки, поскольку для параметра pointer-events установлено значение none .
.plan-group-container:has(.disabled-group) {
opacity: 0.5;
filter: grayscale(100%);
}
.plan-group-container:has(.disabled-section) .button {
pointer-events: none;
border-color: #B5B5B5;
color: var(--text-primary-38-color);
background: var(--input-border-color);
}
Команда специалистов по здравоохранению в Policybazaar реализовала несколько иной вариант использования. У них есть встроенный тест для пользователя, и они используют :has() для проверки статуса флажка вопроса, чтобы узнать, был ли дан ответ. Если да, то применяется анимация для перехода к следующему вопросу.
Код
В примере сравнения планов для проверки наличия класса использовался :has() . Вы также можете проверить состояние элемента ввода, например, флажка, используя :has(input:checked) . На визуализации викторины каждый вопрос в фиолетовом баннере представляет собой флажок. Policybazaar проверяет, был ли дан ответ на вопрос, используя :has(input:checked) , и если да, запускает анимацию с помощью animation: quesSlideOut 0.3s 0.3s linear forwards для перехода к следующему вопросу. Посмотрите, как это работает, в следующем коде.
.segment_banner__wrap__questions {
position: relative;
animation: quesSlideIn 0.3s linear forwards;
}
.segment_banner__wrap__questions:has(input:checked) {
animation: quesSlideOut 0.3s 0.3s linear forwards;
}
@keyframes quesSlideIn {
from {
transform: translateX(50px);
opacity: 0;
}
to {
transform: translateX(0px);
opacity: 1;
}
}
@keyframes quesSlideOut {
from {
transform: translateX(0px);
opacity: 1;
}
to {
transform: translateX(-50px);
opacity: 0;
}
}
Токопедия
Tokopedia использует селектор ` :has() для создания наложенного изображения, если миниатюра товара содержит видео. Если миниатюра товара содержит класс ` .playIcon , добавляется CSS-наложение. Здесь селектор `:has()` используется вместе с вложенным селектором ` & внутри общего класса .thumbnailWrapper , который применяется ко всем миниатюрам. Это создает более модульный и читаемый CSS.

:has() . Код
Приведенный ниже код использует селекторы и комбинаторы CSS ( & и > ) и вложенность с помощью :has() для стилизации миниатюры. Для браузеров, не поддерживающих эту функцию, в качестве запасного варианта используется обычное правило добавления класса CSS. Правило @supports selector(:has(*)) также используется для проверки поддержки браузером. Таким образом, общее впечатление от использования одинаково во всех версиях браузеров.
export const thumbnailWrapper = css`
padding: 0;
margin-right: 7px;
border: none;
outline: none;
background: transparent;
> div {
width: 64px;
height: 64px;
overflow: hidden;
cursor: pointer;
border-color: ;
position: relative;
border: 2px solid ${NN0};
border-radius: 8px;
transition: border-color 0.25s;
&.active {
border-color: ${GN500};
}
@supports selector(:has(*)) {
&:has(.playIcon) {
&::after {
content: '';
display: block;
background: rgba(0, 0, 0, 0.2);
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
}
}
& > .playIcon {
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 50%;
text-align: center;
z-index: 1;
}
}
`;
Что следует учитывать при использовании :has()
Сочетайте :has() с другими селекторами, чтобы создать более сложное условие. Примеры использования селектора `has()` можно посмотреть в соответствующем разделе .
Ресурсы:
- CSS Wrapped 2023
- :has(): селектор семейства
- Демонстрации :has()
- Хотите сообщить об ошибке или предложить новую функцию? Мы хотим услышать ваше мнение !
Ознакомьтесь с другими статьями этой серии, в которых рассказывается о том, как компании электронной коммерции извлекли выгоду из использования новых функций CSS и пользовательского интерфейса, таких как анимация, управляемая прокруткой, переходы между представлениями, всплывающие окна и контейнерные запросы.