Псевдокласс

:has()

Baseline: широко доступно

Выбирает элемент, если внутри него или после него есть элемент, который подходит под селектор в скобках. Позволяет оформить родителя по содержимому.

Пример

Карточка с картинкой
HTML
<div class="card">
  <div class="card__image">Картинка</div>
  <p>Карточка с картинкой</p>
</div>
<div class="card">
  <p>Карточка без картинки</p>
</div>
CSS
.card {
  margin-block-end: 0.5rem;
  padding: 0.5rem;
  border: 1px solid silver;
}

.card:has(.card__image) {
  border-color: royalblue;
  background-color: aliceblue;
}

.card__image {
  padding: 0.5rem;
  background-color: lightsteelblue;
}

Результат

Синтаксис

CSS
:has(<относительные селекторы>) { … }
.card:has(img) { … }        /* внутри есть img */
.card:has(> img) { … }      /* img — прямой ребёнок */
h2:has(+ p) { … }           /* сразу после идёт p */
h2:has(~ .note) { … }       /* где-то дальше среди соседей есть .note */

Значения

<относительные селекторы>
Селекторы через запятую. Каждый может начинаться с комбинатора: пробел (по умолчанию), >, + или ~. Он отсчитывается от элемента, к которому приписан :has(). Элемент подходит, если сработал хотя бы один селектор. Список не прощающий: ошибка в одном селекторе отключает всё правило.

Как понять

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

  • .card:has(img) — карточка, внутри которой есть картинка;
  • h2:has(+ p) — заголовок, за которым сразу идёт абзац, то есть «предыдущий сосед»;
  • body:has(dialog[open]) — страница, на которой открыт диалог.

Условия комбинируются: :has(.a, .b) — есть хотя бы один из, :has(.a):has(.b) — есть оба. А :not(:has(img)) — внутри нет картинок.

Специфичность — как у :is(): по самому сильному селектору в скобках. У .card:has(img) — 0,1,1.

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

Примеры

Форма с ошибкой

Блок формы реагирует на состояние поля внутри: рамка краснеет, пока в поле неверный адрес.

Поле с ошибкой подсвечивает блок
HTML
<div class="field">
  <label for="mail">Почта</label>
  <input id="mail" type="email" value="не адрес">
</div>
CSS
.field {
  padding: 0.5rem;
  border: 2px solid silver;
}

.field:has(:invalid) {
  border-color: crimson;
  background-color: mistyrose;
}

Результат

Заголовок перед абзацем

Подзаголовок прижимается к тексту, только если за ним сразу идёт абзац:

Отступ зависит от следующего элемента
HTML
<p class="title">Подзаголовок перед абзацем</p>
<p>Абзац</p>
<p class="title">Подзаголовок перед списком</p>
<ul><li>Пункт</li></ul>
CSS
.title {
  margin-block: 0 1rem;
  font-weight: bold;
}

.title:has(+ p) {
  margin-block-end: 0.25rem;
  color: teal;
}

Результат

Раскладка по количеству детей

:has() вместе с :nth-child() выбирает контейнер, в котором не меньше четырёх элементов:

Сетка, если элементов четыре и больше
HTML
<ul class="tags">
  <li>Один</li>
  <li>Два</li>
  <li>Три</li>
  <li>Четыре</li>
</ul>
CSS
.tags:has(> :nth-child(4)) {
  display: grid;
  grid-template-columns: 1fr 1fr;
}

Результат

Подсказки

  • :has() пересчитывается при каждом изменении внутри элемента. Широкие условия вроде body:has(.x) на больших страницах замедляют работу, поэтому ставьте :has() на ближайший контейнер и уточняйте селектор внутри.
  • Для проверки поддержки используйте @supports selector(:has(a)). Браузер без поддержки отбросит правило целиком, поэтому не смешивайте :has() с другими селекторами в одном списке.
  • :has() нельзя вкладывать в :has(), но его можно писать внутри :is(), :not() и :where().

Поддержка браузерами

Значения и возможности: :has()
Возможность Chrome Edge Firefox Safari Chrome Android Safari iOS Samsung Internet Opera
:has() 105 105 121 15.4 105 15.4 20.0 91

Яндекс Браузер работает на Chromium и поддерживает то же, что Chrome той же версии. Данные: MDN browser-compat-data 8.1.2, обновлено 17 сентября 2026 г.

Спецификация

См. также

Поиск

Название свойства, селектора или функции — можно по-английски и без двоеточий: hover, gap, clamp.

Меню