В CSS настроен порядок наследования свойств. То есть свойства шрифта от родительского элемента переходят к вложенному. Плюс мы всегда очень просто можем указать стили для любого вложенного элемента, отталкиваясь от родителя. Стандартный пример - стили для выпадающих меню.
Но что делать, если нужно указать стили для родителя или элементов, предшествующих текущему? Вот тут-то и пригодится селектор 4-го уровня в виде псевдокласса :has
.
Этот псевдокаласс мы указываем для родительского класса, который имеет (англ. глагол have - иметь, в 3-м лице - has) некие вложенные селекторы. Однако, несмотря на то, что он вроде бы похож на все остальные селекторы, которые назначают форматирования от родителя ко вложенным элементам, он управляет родительским или предшествующим указанному элементом.
Согласно описанию из MDN,
стили, указанные для элемента с псевдоклассом
:has()
, будут применены, если хотя бы один из относительных селекторов, переданных в качестве аргумента, соответствует хотя бы одному элементу.
А это значит, что с помощью псевдокласса :has()
можно указать стили для родительского или предшествующего элементов. И это очень круто, т.к. в основном CSS настроен на то, чтобы указать стили для вложенных элементов или соседнего элемента(-ов), а тут вы получаете возможность выбирать элементы не ПОСЛЕ указанного, а ДО него.
В настоящее время поддержка селектора:has()
достаточно велика, за исключением части мобильных браузеров.
Если вам нужна проверка поддержки этого селектора, используйте код CSS с директивой @supports
:
1 2 3 4 5 | @supports (selector(:has(*))) { /*...правила... */ } |
Используя селектор :has()
мы можем стилизовать:
- Родительский элемент,
- Первый элемент в диапазоне,
- Последний элемент в диапазоне,
- Все братья и сестры в пределах диапазона.
Выбор родительского элемента
Пример ниже демонстрирует работу псевдокласса :has
по назначению стилей для заголовка, после которого идет абзац, и для ссылки, внутри которой есть тег strong
. Т.е. здесь мы имеем стили не для абзаца p
, следующего после заголовка, или для тега strong
внутри ссылки, а для их родительских элементов с определенным внутренним содержимым.
See the Pen :has selector by Elen (@ambassador) on CodePen.
Давайте теперь рассмотрим другие возможности псевдокласса :has
.
Для начала создадим разметку, в которой есть несколько однотипных элементов с классом .box
и элемент с классом .circle
.
HTML-разметка:
1 2 3 4 5 | <div class="box"></div> <div class="box"></div> <div class="box"></div> <div class="circle"></div> <div class="box"></div> |
Внешний вид без использования псевдокласса:has
.
Код CSS:
1 2 3 4 5 6 7 8 9 10 11 | .box, .circle { display: inline-block; margin: 10px; width: 30px; height: 30px; box-shadow: 1px 1px 3px rgba(0,0,0,.3); background-color: #1E8CBE; } .circle { border-radius: 50%; } |
Выбор предыдущего элемента
Теперь добавим код, который позволит выбрать и увеличить элемент, который находится перед кругом. Здесь в комбинации с псевдоклассом:has
работает соседний селектор.
.box:has(+ .circle) { width: 60px; height: 60px; }
.box:has(+ .circle) selector
Вы можете представить работу этого селектора в такой последовательности:
- выбирает все элементы
.box
. - фильтрует элементы, оставляя только те, которые соответствуют шаблону
.box + .circle
, а это только предыдущий элемент - сосед круга слева.
Выбор n-го предыдущего элемента
Можно использовать соседний селектор для выбора любого конкретного элемента, который предшествует другому. Для этого можно указать его в комбинации с универсальным селектором:
.box:has(+ * + .circle) { width: 60px; height: 60px; }
.box:has(+ * + .circle)
Если вы хотите выбрать третий элемент от искомого внутри родительского элемента, можно использовать такой вариант:
.box:has(+ * + * + .circle) { width: 60px; height: 60px; background-color:#1ebe88; }
.box:has(+ * + * + .circle)
Выбор всех предыдущих элементов
Родственный селектор в виде знака тильды (~
) обычно выбирает все элементы, которые находятся на том же уровне вложенности, что и текущий. Но если мы скомбинируем его с псевдоклассом :has
и поставим перед определенным селектором, то выбор коснется всех предыдущих для него элементов.
Пробуем:
.box:has(~ .circle) { width: 60px; height: 60px; background-color: #f7791d; }
.box:has(~ .circle)
Используем селекторы :has и :not
Псевдокласс has:()
(вместе с :not()
, :where()
, и :is()
) открывает новый мир возможностей при работе со стилями страницы.
Например, вместе с селектором :not
селектор :has
позволит нам отследить отсутствие каких-либо элементов внутри родительского контейнера и применить стили в зависимости от этого.
Ниже вы найдете пример, в котором в зависимости от того, отсутствует ли изображение внутри карточки, меняется верхняя рамка у элемента .card
.
See the Pen card with :has and :not selector by Elen (@ambassador) on CodePen.
Кроме того, с помощью псевдоклассов :has
и :not
мы можем отключать видимость пустого элемента. Ниже вы найдете пример кода, в котором изначально один из контейнеров скрыт, т.к. в нем отсутствует тег form
. Однако с помощью радио-кнопок мы можем его отобразить, причем даже с разным цветом фона. Это еще один пример фильтрации на основе CSS.
See the Pen Selectors :has and :empty by Elen (@ambassador) on CodePen.
Фильтрация товаров с помощью CSS
В примере ниже мы будем комбинировать селектор :has
с селекторами атрибутов, псевдоклассом :checked
для элемента option
для того, чтобы отфильтровать элементы с классом .product
, внутри которых есть элементы с цветовыми классами .black
(.white, .other
), классами цены (.low, .medium, .high
) и брендов (.nike, .adidas
).
Основой для фильтрации является селектор вида:
1 2 3 | .filters:has(option[value="black"]:checked) ~ .products-list .product:not(:has(.black)){ display: none; } |
Тестируйте пример:
See the Pen Choose with :has selector by Elen (@ambassador) on CodePen.
Примеры использования селектора :has
Наведение на изображение в галерее
See the Pen :has() example four by Kevin (@kevinpowell) on CodePen.
Анимация при наведении на элементы списка.
See the Pen Previous/Next Sibling Animation with :has() by Smashing Magazine (@smashingmag) on CodePen.
Пример рейтинга со звездами на основе радио-кнопок от Josetxu
See the Pen Star Rating - CSS :has() by Josetxu (@josetxu) on CodePen.
И еще один рейтинг от Smashing Magazine
See the Pen Star Rating Component with :has() by Smashing Magazine (@smashingmag) on CodePen.