Css parent with child selector

CSS :has() селектор

Также я веду телеграм канал “Frontend по-флотски”, где рассказываю про интересные вещи из мира разработки интерфейсов.

Вступление

Вы когда-нибудь задумывались о селекторе CSS, где вы проверяете, существует ли конкретный элемент внутри родителя? Например, если у компонента карточки есть миниатюра, нам нужно добавить к нему display: flex. Это было невозможно в CSS, но теперь у нас будет новый селектор CSS :has, который поможет нам выбрать родителя определенного элемента и многое другое.

В этой статье я объясню проблему, которую решает :has, как он работает, где и как мы можем его использовать с некоторыми вариантами использования и примерами, и, самое главное, как мы можем использовать его уже сегодня.

Проблема

Возможность стилизовать родительский элемент отсутствует. Мы должны создавать классы CSS и переключать их в зависимости от того, что нам нужно.

Читайте также:  Php curl extension https

Рассмотрим следующий базовый пример.

У нас есть компонент карточки в двух вариациях: 1) С изображением 2) Без изображения. В CSS мы могли бы сделать что-то вроде этого:

/* A card with an image */ .card < display: flex; align-items: center; gap: 1rem; >/* A card without an image */ .card--plain

Как вы видели выше, мы создали класс специально для карточки без изображения, поскольку нам не нужен display: flex на родительском элементе. Вопрос в том, можем ли мы это сделать в CSS, без второго класса?

Ну, вот где CSS :has приходит на помощь. Это может помочь нам проверить, есть ли у элемента .card изображение .card__image или нет.

Например, мы можем проверить, есть ли у карточки изображение, и если да, то нам нужно применить flexbox.

Знакомство с :has селектором

Согласно спецификации CSS, селектор :has проверяет, содержит ли родитель хотя бы один конкретный элемент или выполняется ли условие, например, если инпут сфокусирован.

Вернемся к предыдущему фрагменту кода.

Мы проверяем, содержит ли родительский элемент .card дочерний элемент .card__image . Рассмотрим следующий рисунок:

Проще говоря, приведенный выше CSS эквивалентен следующему: «Есть ли в карточке элемент .card__image ?»

Разве это не восхитительно? В CSS есть логика!

Селектор :has не только про родителя

Речь идет не только о проверке того, содержит ли родитель дочерний элемент, но мы также можем проверить, следует ли за элементом, например,

. Рассмотрим следующее:

Это проверяет, следует ли непосредственно за

. Или мы можем использовать его с элементом формы, например, чтобы проверить, есть ли сфокусированный инпут.

Поддержка браузерами

На момент написания статьи CSS :has работал в Safari 15.4 и в Chrome Canary. Следите за поддержкой на Can I use.

Можем ли мы использовать это внутри @supports?

Хватит теории, давайте перейдем к примерам использования!

Примеры использования CSS :has

Заголовок раздела

Когда я работаю над заголовком раздела, у меня в основном будет два варианта: один только с заголовком, а другой содержит и заголовок, и якорную ссылку.

В зависимости от того, есть ли ссылка или нет, я хочу оформить его по-разному.

  

Latest articles

.section-header < display: flex; justify-content: space-between; >/* If there is a link, add the following */ .section-header:has(> a)

Компонент карточки, Пример 1

Вернемся немного назад к примеру с исходной картой. У нас есть два варианта, один с изображением, а другой без него.

Мы даже можем проверить, нет ли на .card изображения, и применить определенные стили. В нашем случае это border-top .

Без :has нам пришлось бы иметь два класса, чтобы сделать это.

Компонент карточки, Пример 2

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

Когда действия карточки имеют две разные обёртки для действий, мы хотим активировать display: flex следующим образом (пожалуйста, не обращайте внимания на приведенную ниже разметку, она предназначена исключительно для демонстрационных целей!).

.card__actions:has(.start, .end)

Вот что нам придётся делать без :has.

.card--with-actions .card__actions

Компонент карточки, Пример 3

Вам когда-нибудь приходилось сбрасывать border-radius для компонента в зависимости от того, есть ли изображение или нет? Это идеальное использование CSS :has.

Рассмотрим следующий рисунок. Когда изображение удалено, border-radius верхнего левого и правого углов равен нулю, что выглядит странно.

.card:not(:has(img)) .card__content < border-top-left-radius: 12px; border-top-right-radius: 12px; >.card img < border-top-left-radius: 12px; border-top-right-radius: 12px; >.card__content

Вот что нам придётся написать без использования :has.

Компонент фильтрации

В этом примере у нас есть компонент с несколькими параметрами. Когда ни один из них не отмечен, кнопки сброса нет. Однако, когда хотя бы один отмечен, нам нужно показать кнопку сброса.

Мы можем легко сделать это с помощью CSS :has.

.btn-reset < display: none; >.multiselect:has(input:checked) .btn-reset

Мы вообще не можем сделать это в CSS без :has. Это один из сценариев, когда мы откажемся от Javascript, если :has будет поддерживаться в современных браузерах.

Показать или скрыть элементы формы по условию

Возможно, нам потребуется показать конкретное поле формы на основе предыдущего ответа или выбора. В этом примере нам нужно показать поле «other», если пользователь выбрал «other» в меню выбора.

С помощью CSS :has мы можем проверить, выбрано ли в меню значение «other», и показать поле «other» на основе этого.

.other-field < display: block; >form:has(option[value="other"]:checked) .other-field

Разве это не восхитительно? Нам не нужно беспокоиться об исходном порядке HTML, если поле выбора и формы находится внутри родительского элемента .box .

Элемент навигации с подменю

В этом примере у нас есть элемент навигации с подменю, которое появляется при наведении или фокусе.

Обёртка для шапки

При создании компонента заголовка мы можем быть уверены в том, хотим ли мы, чтобы заголовок занимал всю ширину страницы или был в обёртке.

В любом случае нам нужно применить flexbox для распределения элементов заголовка определенным образом. Если .wrapper есть, мы применим к нему стили. Если нет, то применим их непосредственно к элементу .site-header .

.site-header:not(:has(.wrapper)) < display: flex; justify-content: space-between; align-items: center; padding-inline: 1rem; >/* If it has a wrapper */ .site-header .wrapper

Акцент на алертах

На некоторых панелях мониторинга может быть важное предупреждение, о котором должен знать пользователь. В этом случае оповещения на странице может быть недостаточно. В таком случае мы могли бы, например, добавить красную рамку и приглушенный красный цвет фона к элементу заголовка.

Это повысит вероятность того, что пользователь быстро заметит предупреждение.

С помощью CSS :has мы можем проверить, есть ли предупреждение в элементе .main , и если да, мы можем добавить следующие стили в заголовок.

Смена темы

Мы можем использовать CSS :has для изменения цветовой схемы веб-сайта. Например, если у нас есть несколько тем, созданных с помощью переменных CSS, мы можем изменить их через

И когда мы выбираем другой вариант из списка, вот что происходит в CSS. В зависимости от выбранной опции переменные CSS будут изменены.

html:has(option[value="blueish"]:checked)

Стилизация сгенерированного HTML

В некоторых случаях у нас нет никакого контроля над HTML. Например, в теле статьи. Система управления контентом (CMS) может генерировать элементы неожиданным образом, или автор может встроить видео или что-то в этом роде.

Предположим, что мы хотим выбрать тот , за которым не следует абзац, и увеличить интервал под ним.

Или вам нужно выбрать , за которым следует и что-то сделать. Такие ситуации не могут быть обработаны без CSS :has!

Кнопка с иконкой

В этом примере у нас есть стиль кнопки по умолчанию. Когда у нас есть иконка, мы хотим использовать flexbox для центрирования и выравнивания содержимого кнопки.

Несколько кнопок

В дизайн-системе нам часто требуется группа кнопок. Если у нас есть более двух кнопок, последняя должна отображаться на дальней противоположной стороне.

Для этого мы можем использовать количественные запросы. Следующий CSS проверит, равно ли количество кнопок трём или больше, и если да, последний элемент будет сдвинут вправо с помощью margin-left: auto .

.btn-group < display: flex; align-items: center; gap: 0.5rem; >.btn-group:has(.button:nth-last-child(n + 3)) .button:last-child

Информационные модули

Я получил этот пример из дизайна pinterest. Когда инпут имеет ошибку, мы хотим, чтобы заголовок изменился и указывал на это.

.module:has(.input-error) .headline

Изменить сетку в зависимости от количества элементов

С сеткой CSS мы можем использовать функцию minmax() для создания отзывчивых элементов сетки с автоматическим размером. Однако этого может быть недостаточно. Мы также хотим изменить сетку в зависимости от количества элементов.

Рассмотрим следующий рисунок.

Когда у нас будет 5 элементов, последний будет перенесен в новую строку.

Мы можем преодолеть это, проверив, содержит ли .wrapper 5 или более элементов. Опять же, здесь используется концепция количественных запросов.

.wrapper:has(.item:nth-last-child(n + 5))

Figure и Figcaption

В этом примере у нас есть HTML . Если есть стиль должен немного отличаться:

Заключение

Мне не терпится увидеть, что вы создадите с помощью CSS :has. Сценарии использования в этой статье — лишь малая часть! Я уверен, что мы обнаружим много полезных применений по пути.

Как говорится, самое подходящее время для изучения CSS. Я очень, очень взволнован тем, что будет дальше. Большое спасибо за чтение!

Источник

Parent Selection in CSS: how the CSS has selector works

CSS stands for cascading stylesheets, which basically means things later on in the page take precedence over things earlier (with some major caveats). This also applies to how we select elements — from parent to child, with no way to select parents, until now.

In the CSS Selectors 4 specification, CSS introduces a new selector called :has() , which finally lets us select parents. What that means is we’ll be able to target a CSS element which has specific children within it. This is already supported in Safari, and is also in Chrome 105. The full support table is shown below:

Data on support for the css-has feature across the major browsers from caniuse.com

With support increasing, in this article I will focus on how CSS parent selection works, and how you can do it today where support is available. In the meantime, if you require full support in all browsers, you can also implement this polyfill until native CSS support is available.

How Parent Selectors work in CSS

In CSS, if we want to select something, we use selectors that descend the DOM. For example, selecting a p tag within a div tag looks like this:

Until now, we couldn’t really select the div tags which had p tags within them, though, and this meant we had to resort to Javascript. The main reason this wasn’t implemented in CSS is because it’s quite an expensive operation to do. CSS is relatively fast to parse, but selecting parent tags requires a relatively significant larger amount of processing.

Using the :has selector, we can now select div elements which have a p children, or any normal combination of selectors. For example, selecting a div with a child p now looks like this:

/* Makes the div color: red; */ div:has(p)   color: red; > 

This will make any div with a child p red.

Combining parent selection with other selectors

Just like any other CSS selector, we can combine this for specific circumstances. For example, if you want to select only div tags which have direct span children:

As the vocabulary of :has suggests, it is not just limited to parent selection. For example, below we can select a span which :has a sibling div :

Or even, selecting an element which does not have a child, by using the :not() selector. For example, the following will select any div which does not have a p child:

Selecting elements which only contain text in CSS

One very common problem in CSS is that the :empty tag does not select elements which contain any text — so sometimes an element can contain one space, and :empty will not apply. The :has selector gives us the power to select elements which only contain text nodes, and no other child elements.

Although this is not the perfect solution for simply :empty elements with spaces (as this will select any element with just text and no additional HTML DOM elements) — it does give us the ability to select DOM elements with only text nodes, which was not previously possible. We can achieve this with the following code:

div:not(:has(*))   background: green; > 

Conclusion

With the addition of :has() selector support in Chrome 105, parent selection is quickly becoming a reality that we will soon be able to use on real life projects. As of now, with Safari support, it’s easy to test and see how it will work in the future. This has the additional benefit of letting us cut back on Javascript solutions to parent selection which is quite common in many applications and products.

You can even start using :has today, if you also implement this polyfill, and then remove the polyfill once native support comes to Chrome and other browsers.

More Tips and Tricks for CSS

Источник

Оцените статью