:has

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

Кратко

Секция статьи "Кратко"

Псевдокласс :has() позволяет выбрать элемент, уточнив основной селектор дополнительным, и при этом не увеличив его «вес». В отличие от привычных селекторов, правило применится только к тому селектору, который был описан до :has().

Пример

Секция статьи "Пример"

Правила применятся только к такому <dt>, за которым сразу следует другой элемент <dd>:

        
          
          dt:has(+ dd) {  /* Стили */}
          dt:has(+ dd) {
  /* Стили */
}

        
        
          
        
      

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

Как, например, найти такие ссылки, внутри которых есть изображения:

        
          
          a:has(img) {  /* Стили */}
          a:has(img) {
  /* Стили */
}

        
        
          
        
      

Как пишется

Секция статьи "Как пишется"
        
          
          selector1:has(selector2) {  /* … */}
          selector1:has(selector2) {
  /* … */
}

        
        
          
        
      

selector1 — необязательный селектор (если не указан — правило применится ко всем подходящим элементам). Аргумент selector2 в :has() описывает селектор относительно своей точки отсчёта — selector1.

Как это понять

Секция статьи "Как это понять"

По сути псевдокласс :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%;
}