:has()

Уникальный селектор, позволяющий стилизовать родителя при наличии конкретного ребёнка.

Время чтения: меньше 5 мин

Кратко

Скопировано

Функция-псевдокласс :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:has(selector2, selector3) браузер проверяет аналогично: 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%;
}

        
        
          
        
      

Realetive советует

Скопировано

🛠 До появления псевдокласса :has() единственной возможностью управлять проверкой вложенного селектора был JavaScript.