Кратко
СкопированоФункция-псевдокласс :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:
## Цитаты Далай ЛамыЛюди были созданы для того, чтобы их любили,а вещи были созданы для того, чтобы ими пользовались.Мир в хаосе, потому что все наоборот.![Фото Далай Ламы](https://yoursite.com/dalai-lama.jpg)Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?»Задавая этот вопрос всякий раз перед принятием решения,мы перемещаем свое внимание с того, в чем мы себе отказываем,на то, к чему мы стремимся.Далай Лама
## Цитаты Далай Ламы Люди были созданы для того, чтобы их любили, а вещи были созданы для того, чтобы ими пользовались. Мир в хаосе, потому что все наоборот. ![Фото Далай Ламы](https://yoursite.com/dalai-lama.jpg) Принимая решение, спрашивайте себя: «А сделает ли это меня счастливым?» Задавая этот вопрос всякий раз перед принятием решения, мы перемещаем свое внимание с того, в чем мы себе отказываем, на то, к чему мы стремимся. Далай Лама
Эта разметка превратится в такой 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.