Привет, друзья! Представляю вашему вниманию перевод этой замечательной статьи, посвященной продвинутому использованию нового CSS-селектора :has(). :has() предоставляет возможность "заглядывать вперед" с помощью CSS и стилизовать родительский элемент (предка). Этот селектор может быть легко расширен для стилизации одного или нескольких дочерних элементов (потомков). Регистрация состояний или позиций элемента позволяет стилизовать почти любую комбинацию элементов как уникальных или входящих в определенный диапазон. Обратите внимание: на сегодняшний день :has() поддерживается не всеми браузерами, поэтому использовать его в производственных приложениях пока рано. Комбинатор (combinator) — это специальный символ, определяющий тип отношений между частями селектора. Основными комбинаторами являются: Первым этапом создания сложного селектора является добавление псевдокласса к одной или более частям селектора. Псевдокласс определяет специальное состояние элемента, например :hover. Псевдокласс :has() считается функциональным, поскольку принимает параметр. Точнее, он принимает список селекторов, как простых вроде img, так и сложных (с комбинаторами) вроде img + p. :has() — это один из четырех функциональных псевдоклассов, наряду с :is(), :where() и :not(). :is() и :where() предназначены для группировки селекторов и управления специфичностью. При использовании :is() вес всего селектора определяется селектором из списка с наивысшей специфичностью. При использовании :where() специфичность всего селектора является нулевой, что облегчает его перезапись более поздними правилами в каскаде. Кроме того, :is() и :where() являются прощающими селекторами. Это означает, что браузер "прощает" присутствие в списке невалидных селекторов, т.е. селекторов, которые он не понимает. Браузер просто обрабатывает селекторы, которые понимает вместо того, чтобы игнорировать всю группу. Пример использования :is() для группировки селекторов: article :is(h1, h2, h3) — выбираем все элементы h1, h2 и h3, которые являются потомками элемента article. Псевдокласс :not() раньше принимал только один селектор. Спецификация Selectors Level 4 разрешила ему принимать список селекторов. Определение специфичности :not() аналогично :is(). Еще одна важная особенность: символ * (универсальный селектор — universal selector) в :is(), :where() и :not() фактически указывает на цель селектора. Это позволяет проверять предыдущих сиблингов или предков цели селектора. Например, в img:not(h1 + *) мы выбираем изображения, которые не следуют непосредственно за h1, а в p:is(h2 + *) мы выбираем параграфы, только если они следуют непосредственно за h2. Прим. пер.: с вашего позволения я пропущу раздел "Полифил для :only-of-selector", поскольку параграфы, стилизуемые в примере с помощью селектора .highlight:not(:has(~ .highlight)):not(.highlight ~ *) могут быть стилизованы просто через .highlight. :has() позволяет стилизовать предыдущих сиблингов на основе того, что следует за ними. Для демонстрации этой возможности создадим список элементов. При наведении курсора на элемент списка, он увеличивается в размерах. Элементы перед и после него также немного увеличиваются. Оставшиеся элементы уменьшаются в размерах. Все элементы, кроме "наведенного", становятся немного прозрачными. Первый селектор должен совпадать с элементом списка перед наведенным. Этого можно достичь с помощью :has(). Следующее правило гласит "выбери элемент списка, за которым непосредственно следует наведенный элемент": Добавляем к этому селектор следующего непосредственного сиблинга и применяем стили: Третий сложный селектор представляет собой комбинацию :has() и :not(). Этот селектор применяется в случае, когда курсор наведен на одного из прямых потомков ul (элемент списка), ко всем элементам списка, кроме наведенного и элементов, перед и после него. Рассмотрим пример диапазона потомков, таких как элементы между h2 и hr в следующем примере: С помощью :has() мы можем стилизовать: Эти селекторы будут во многом полагаться на комбинатор общих сиблингов, который позволяет "заглядывать вперед" и стилизовать несколько сиблингов за раз. Следующее правило гласит "выбери сиблинга, следующего непосредственно за h2 при условии, что за ним следует другой h2", что совпадает с параграфом, следующем непосредственно за первым h2 в примере: Следующее правило гласит "выбери элемент, следующий за h2 при условии, что за ним непосредственно следует другой h2", что совпадает с параграфом перед вторым h2 в примере: Следующее правило гласит "выбери все элементы, следующие за hr, при условии, что за ними следует hr", что совпадает с тремя параграфами между hr в примере: Обратите внимание: это работает только для одного диапазона внутри родительского элемента. Предположим, что у нас имеется список элементов, в котором два элемента имеют атрибут data-range: Для выбора начала и конца диапазона мы можем использовать атрибут data-range. Затем мы можем использовать созданный нами в предыдущем разделе селектор для выбора всех сиблингов внутри диапазона: Следующее правило гласит "выбери элемент с атрибутом data-range, за которым следует сиблинг с таким же атрибутом", что совпадает с первым элементом диапазона: Следующее правило гласит "выбери элемент с атрибутом data-range, за которым непосредственно следует элемент с таким же атрибутом", что совпадает с последним элементом диапазона: Ключом для стилизации нескольких диапазонов является различение начала и конца диапазонов. Мы снова используем атрибуты data-range, но в этот раз со значениями start и end: Это позволяет упростить селекторы первого и последнего элементов диапазона: Стилизуем первый и последний элементы внутри диапазона. Сначала добавляем значения дата-атрибутов start и end. Затем добавляем условие, что стили не должны применяться к началу и концу диапазона, с помощью :not([data-range]): Как нам выбрать элементы внутри диапазона? Попробуем так: Результат: 
 Селектор работает не так, как ожидается: стили применяются к элементам за пределами диапазона. Для решения этой проблемы нужно добавить сложное условие AND с помощью :not() для исключения элементов за пределами диапазона. Следующее правило гласит "не выбирать элементы, следующие за , за которыми следует ": Полный селектор выглядит так (несмотря на то, что он длинный и сложный, до :has() такое вообще нельзя было провернуть): Создадим компонент "звездного" рейтинга. "Звезда" будет элементов input типа radio (радио-кнопкой), обладающей состоянием :checked: Функционал рейтинга: Следующий набор селекторов применяется ко всем состояниям, где мы хотим заливать цветом звезду или звезды до выбранной звезды (:checked). Правило обновляет набор кастомных свойств, влияющих на фигуру звезды, созданную с помощью комбинации псевдоэлементов ::before и ::after на label.star. Проще говоря, это правило выбирает диапазон звезд от первой до наведенной или от первой до выбранной: Далее мы хотим, чтобы цвет заливки диапазона звезд от наведенной до выбранной и самой выбранной звезды был немного светлее: :has() также позволяет визуализировать границы элементов на основе их состояния. Если у нас имеется набор чекбоксов (<input type="checkbox">), мы можем использовать состояние :checked для определения границ вокруг выбранных и невыбранных элементов. Допустим, что мы хотим, чтобы выбранный чекбокс имел границы и зеленый фон. При этом, группа выбранных чекбоксов должна иметь общие границы: первый чекбокс группы должен иметь только верхнюю границу, последний — только нижнюю, остальные — только боковые. Границы должны быть скругленными. Последний чекбокс группы также должен иметь небольшую тень. Нам необходимо создать правила для обработки верхнего, нижнего и промежуточных чекбоксов в выбранной группе. Одиночные элементы должны получать все стили. В нашей разметке все чекбоксы будут обернуты в подпись (<label>), поэтому все селекторы будут начинаться с label:has(:checked) для определения того, что подпись содержит выбранный чекбокс. Следующее правило гласит "выбери выбранный элемент, перед которым нет другого выбранного элемента", что совпадает с верхним выбранным чекбоксом группы и одиночным выбранным чекбоксом: Следующее правило гласит "выбери выбранный элемент, который не следует за другим выбранным элементом", что совпадает с нижним выбранным чекбоксом и одиночным выбранным чекбоксом: Для стилизации промежуточных выбранных чекбоксом можно использовать просто label:has(:checked), но давайте воспользуемся расширенным селектором, который уже имеется в нашем распоряжении. Следующее правило гласит "выбери подписи с выбранными чекбоксами, которые следуют за сиблингами с выбранными чекбоксами", что совпадает со всеми выбранными чекбоксами, кроме последнего. Для выбора последнего чекбокса мы добавляем к этому только что созданный нами селектор: Все демонстрации из статьи доступны в этой коллекции на CodePen. Ссылки на материалы для дополнительного изучения: Надеюсь, что вы, как и я узнали что-то новое и не зря потратили время. Благодарю за внимание и happy coding!  JavaScript Developer