Кратко
СкопированоФункция-псевдокласс :hasпозволяет уточнить основной селектор дополнительным. Это единственный способ выбрать элемент на основе дочернего или соседнего элемента посредством CSS.
Пример
СкопированоПрименяем стили ко всем ссылкам, которые содержат изображения:
a:has(img) { /* Стили */}
a:has(img) {
/* Стили */
}
Стили применятся только к такому <dt>, за которым сразу следует элемент <dd>:
dt:has(+ dd) { /* Стили */}
dt:has(+ dd) {
/* Стили */
}
Как пишется
Скопированоselector1 — необязательный селектор (если не указан — правило применится ко всем подходящим элементам). Аргумент selector2 в :has описывает селектор относительно своей точки отсчёта — selector1:
selector1:has(selector2) { /* Стили */}
selector1:has(selector2) {
/* Стили */
}
Если .class — валидный селектор, а #top — нет, то selector будет уточнён за счёт .class:
selector:has(.class, #top) { /* Стили */}
selector:has(.class, #top) {
/* Стили */
}
Как понять
СкопированоФункция-псевдокласс :has принимает один или несколько селекторов любой сложности в качестве аргумента. В отличие от :is и :where правило применится только к тому селектору, который был описан до :has
Подсказки
Скопировано💡 Использование псевдокласса :has влияет на специфичность целевого селектора, т. е. при расчёте веса целевого селектора учитывается селектор, переданный в аргументах.
💡 Переданные через запятую селекторы selector1 браузер проверяет аналогично: selector2 или selector3. Допустим, что в примере ниже оба переданных в :has селектора являются действительными. Тогда selector будет уточнён за счёт #link, так как вес #link больше веса .content:
selector:has(.content, #link) { /* Стили */}
selector:has(.content, #link) {
/* Стили */
}
💡 Есть возможность соединять селекторы. Такую запись браузер интерпретирует аналогично: selector2 и selector3. В случае валидности селекторов selector2 и selector3, браузер применит стили к selector1:
selector1:has(selector2):has(selector3) { /* Стили */}
selector1:has(selector2):has(selector3) {
/* Стили */
}
💡 Псевдокласс :has не может быть вложен в другой :has, так как это может привести к циклическим запросам при выполнении поиска селектора.
💡 Нельзя использовать псевдоэлементы в качестве аргументов в :has, а также в качестве целевого селектора.
На практике
Скопированосоветует
Скопировано🛠 Бывает, что контент какого-то блока вашей HTML-страницы генерируется из Markdown-разметки. Это особенно часто встречается на сайтах, созданных при помощи генераторов сайтов вроде 11ty. Вы не можете добавить в сгенерированный HTML-код классы, идентификаторы или дата-атрибуты. Псевдокласс :has может решить достаточно сложную ситуацию с непредвиденным появлением обёрток вокруг элементов.
Вот типовой кусок разметки Markdown:
## Цитаты Далай ЛамыЛюди были созданы для того, чтобы их любили,а вещи были созданы для того, чтобы ими пользовались.Мир в хаосе, потому что все наоборот.Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?»Задавая этот вопрос всякий раз перед принятием решения,мы перемещаем своё внимание с того, в чём мы себе отказываем,на то, к чему мы стремимся.Далай Лама
## Цитаты Далай Ламы
Люди были созданы для того, чтобы их любили,
а вещи были созданы для того, чтобы ими пользовались.
Мир в хаосе, потому что все наоборот.

Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?»
Задавая этот вопрос всякий раз перед принятием решения,
мы перемещаем своё внимание с того, в чём мы себе отказываем,
на то, к чему мы стремимся.
Далай Лама
Эта разметка превратится в такой HTML (я поместил его внутрь секции — это похоже на реальное использование):
<section class="content"> <h2>Цитаты Далай Ламы</h2> <p> Люди были созданы для того, чтобы их любили, а вещи были созданы для того, чтобы ими пользовались. Мир в хаосе, потому что все наоборот. </p> <p> <img src="https://yoursite.com/dalai-lama.jpg" alt="Фото Далай Ламы" > </p> <p> Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?» Задавая этот вопрос всякий раз перед принятием решения, мы перемещаем своё внимание с того, в чём мы себе отказываем, на то, к чему мы стремимся. </p> <p>Далай Лама</p></section>
<section class="content">
<h2>Цитаты Далай Ламы</h2>
<p>
Люди были созданы для того, чтобы их любили,
а вещи были созданы для того, чтобы ими пользовались.
Мир в хаосе, потому что все наоборот.
</p>
<p>
<img
src="https://yoursite.com/dalai-lama.jpg"
alt="Фото Далай Ламы"
>
</p>
<p>
Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?»
Задавая этот вопрос всякий раз перед принятием решения,
мы перемещаем своё внимание с того, в чём мы себе отказываем,
на то, к чему мы стремимся.
</p>
<p>Далай Лама</p>
</section>
Изображение обёрнуто в абзац, это неудобно, но так работает конвертер. Это усложняет стилизацию. Например, мы хотим поставить изображение справа от первого абзаца, а остальные абзацы не трогать. Псевдокласс :has — помощник в таких случаях.
Выбираем абзац, следом за которым сразу идёт другой абзац с вложенным изображением:
.content p:has(+ p > img) { display: inline-block; vertical-align: top;}
.content p:has(+ p > img) {
display: inline-block;
vertical-align: top;
}
Если знаки + и > в селекторах вызывают недоумение, то почитайте статью о комбинированных селекторах.
Теперь выберем абзац с вложенным изображением:
.content p:has(img) { display: inline-block; vertical-align: top; width: 300px;}
.content p:has(img) {
display: inline-block;
vertical-align: top;
width: 300px;
}
Подгоним изображение под ширину родителя:
.content img { width: 100%;}
.content img {
width: 100%;
}
советует
Скопировано🛠 До появления псевдокласса :has единственной возможностью управлять проверкой вложенного селектора был JavaScript.