Псевдокласс :has()

Влад Мержевич

При изучении комбинаций селекторов мы столкнулись с тем, что с их помощью можно выбрать дочерний или следующий братский элемент, но никак не родителя или предыдущий элемент.

Селекторы потомка и дочерние селекторы читаются слева направо, следующая запись означает, что следует найти все элементы <button>, внутри них <span> и стиль применить уже к ним.

button > span { color: red; }

В CSS не существует селектора родителя, позволяющего применить стиль к родителю при наличии у него указанного дочернего элемента. Роль такого селектора выполняет псевдокласс :has().

Псевдокласс :has() применяет стилевые правила к элементу, если у него есть указанный потомок или родственный элемент. Это даёт возможность задавать стили родителя на основе его дочерних элементов. К примеру, следующая запись означает применить стиль к элементу <li>, если внутри него располагается элемент <a>.

li:has(a) { background-color: tomato; }

Вот несколько примеров использования псевдокласса :has().

a:has(> img) {…}

Применяет стиль к элементам <a>, которые являются родителями для <img>.

button:has(.icon)

Применяет стиль к элементам <button>, внутри которых есть элемент с классом .icon.

h1:has(+ h2)

Применяет стиль к элементам <h1>, после которых идёт элемент <h2>.

li:has(+ li:hover)

Применяет стиль к предыдущему пункту списка (<li>) при наведении.

.card:not(:has(img))

Применяет стиль ко всем элементам с классом .card, внутри которых нет элемента <img>.

article:has(audio, video)

Применяет стиль к элементам <article> внутри которых есть элемент <audio> или <video>.

:is(h1, h2, h3):has(+ p)

Применяет стиль к элементам <h1>, <h2>, <h3>, после которых сразу идёт элемент <p>.

Как видно из приведённых примеров, внутрь :has() можно вставлять группу селекторов, дочерние селекторы, смежные селекторы и др.

Внутри :has() не разрешается вставлять другой :has(), а также псевдоэлементы (::first-line, ::before, ::after и др.).

:has(:has(li)) { /* Неверно */ }
:has(::before) { /* Неверно */ }

В примере 1 при наведении курсора мыши на картинку все остальные изображения в блоке .photo становятся полупрозрачными. Это делается с помощью комбинации псевдоклассов :has(), :not() и :hover().

Пример 1. Использование :has()

<!DOCTYPE html>
<html lang="ru">
 <head>
  <meta charset="utf-8">
  <title>:has</title>
  <style>
   .photo:has(img:hover) img:not(:hover) {
    opacity: 0.3; /* Значение прозрачности */
   }
  </style>
 </head>
 <body>
  <div class="photo">
   <img src="image/thumb1.jpg" alt="">
   <img src="image/thumb2.jpg" alt="">
   <img src="image/thumb3.jpg" alt=""> 
   <img src="image/thumb4.jpg" alt="">
  </div>
 </body>
</html>

Итоги

  • Псевдокласс :has() позволяет выбрать элементы на основе того, содержат ли они определённый дочерний элемент или нет.
  • :has() допустимо комбинировать с группой селекторов (p:has(b, i)), селектором потомка (li:has(a)), дочерним селектором (li:has(>li)), смежным селектором (li:has(+ li)) и др.
  • :has() может применяться совместно с другими псевдоклассами, например, :hover (span:has(a:hover)), :is() (:is(h1, h2):has(+ p)), :not() (figure:not(:has(figcaption)) ) и др.
  • Внутрь :has() нельзя вставлять другой :has(), а также псевдоэлементы (::first-line, ::before, ::after и др.).

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.