Использование CSS-селектора :has() на примерах

Что такое CSS-псевдокласс :has(), как он работает и какими браузерами поддерживается? Разобрали на понятных примерах.

13К открытий14К показов

Итак, :has() — это CSS-псевдокласс родительского селектора. Другими словами, с помощью :has() можно изменить родительский элемент, содержащий определённый дочерний элемент либо элемент, следующий за ним.

А вот определение из документации:

CSS псевдокласс :has() отображает элемент в том случае, если любой из селекторов, переданный в качестве параметра (относительно :scope), соответствует хотя бы одному элементу.

Всё ещё не очень понятно, правда? Давайте обратимся к практическим примерам.

Как использовать CSS-селектор :has()?

Рассмотрим следующий HTML-код с двумя родственными элементами с классом everybody. Как бы вы выбрали тот, у которого есть потомок с классом a-good-time?

			<div class="everybody">
  <div>
    <div class="a-good-time"></div>
  </div>
</div>

<div class="everybody"></div>
		

С CSS-селектором :has() это можно реализовать следующим образом:

			.everybody:has(.a-good-time) {
  animation: party 21600s forwards;
}
		

Это выбирает первый экземпляр .everybody и применяет к нему animation. В этом примере целью является элемент с классом everybody. Условием является наличие потомка с классом a-good-time.

			<target>:has(<condition>) { <styles> }
		

Но :has() гораздо больше возможностей. Вот некоторые из них.

Выбрать anchor, которые не имеют прямого потомка SVG:

			a:not(:has(> svg)) { ... }
		

Выбрать label, у которых есть родственный input:

			label:has(+ input) { … }
		

Выбрать documentElement, в котором некое состояние присутствует в DOM:

			:root:has(.menu-toggle[aria-pressed=”true”]) { … }
		

И так далее.

Совместимость :has() с браузерами

Не стоит забывать и о совместимости. Поскольку данный псевдокласс является нововведением, его, к сожалению, поддерживают не все браузеры:

CSS-селектор :has() на практике

Это реализация без единой строчки на JavaScript. Для начала можете посмотреть и самостоятельно протестировать пример, который реализован в CodePen:

Теперь рассмотрим его подробнее. Итак, CSS-псевдокласс :hover срабатывает, когда пользователь наводит на элемент мышью, но при этом активировать его необязательно.

Красивая плавность в примере заключается в создании набора кастомных свойств на основе сглаживающей кривой (easing curve). В нашем случае это:

			:root {
  --lerp-0: 1;
  --lerp-1: 0.5625;
  --lerp-2: 0.25;
  --lerp-3: 0.0625;
  --lerp-4: 0;
}
		

Затем, чтобы применить это, нам нужны правила, которые обновляют пользовательское свойство --lerp для :hover или :focus для каждого элемента или блока. Код ниже предназначен для выбора пяти блоков с комбинацией родственных комбинаторов (+) и :has().

			:is(.block:hover, .block:focus-visible) {
  --lerp: var(--lerp-0);
  z-index: 5;
}
.block:has( + :is(.block:hover, .block:focus-visible)),
:is(.block:hover, .block:focus-visible) + .block {
  --lerp: var(--lerp-1);
  z-index: 4;
}
.block:has( + .block + :is(.block:hover, .block:focus-visible)),
:is(.block:hover, .block:focus-visible) + .block + .block {
  --lerp: var(--lerp-2);
  z-index: 3;
}
.block:has( + .block + .block + :is(.block:hover, .block:focus-visible)),
:is(.block:hover, .block:focus-visible) + .block + .block + .block {
  --lerp: var(--lerp-3);
  z-index: 2;
}
.block:has( + .block + .block + .block + :is(.block:hover, .block:focus-visible)),
:is(.block:hover, .block:focus-visible) + .block + .block + .block + .block {
  --lerp: var(--lerp-4);
  z-index: 1;
}
		

Последнее, что нужно сделать, это применить всё к самим блокам. Поскольку блоки выложены с помощью flexbox, можно использовать значение --lerp, чтобы изменить flex каждого блока, и translation для каждого элемента:

			.blocks {
  display: flex;
}
.block {
  transition: flex 0.2s;
  flex: calc(0.2 + (var(--lerp, 0) * 1.5));
}
.block__item {
  transition: transform 0.2s;
  transform: translateY(calc(var(--lerp) * -75%));
}
		

А вот сами значения --lerp сгенерированы с помощью утилиты GSAP для распределения значений с помощью сглаживающей кривой.

Следите за новыми постами
Следите за новыми постами по любимым темам
13К открытий14К показов