Использование CSS :has() в реальных условиях

Источник: «Some little ways I’m using CSS :has() in the real world»
Я создал несколько примеров сниппетов :has(), используемых в реальных клиентских проектах.

Сейчас много шума вокруг нового CSS псевдокласса :has(). Это то, о чем мы мечтали годами: возможность выбирать родительские элементы!

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

Я не на 100% уверен, что :has() — это та серебряная пуля, о которой говорят другие. Я всё ещё регулярно использую исключения CUBE, но я также нахожусь в привилегированном положении, когда проекты, над которыми я работаю в студии, не ограничивают доступ к разметке. Я считаю :has() более удобным для небольших доработок, но если у вас нет доступа к разметке, то это действительно серебряная пуля.

Учитывая всё это, я решил привести несколько примеров использования :has() в реальных проектах клиентов, чтобы вы могли взглянуть на них в реальном мире. Давайте начнём.

Корректировка макета баннера

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

Единственным отличием от шаблона по умолчанию стало наличие элемента <button>, так что быстрый запрос :has() позволит нам в мгновение ока применить гибкий макет.

.banner {
background: var(--color-primary);
color: var(--color-light);
font-weight: var(--font-bold);
text-align: center;
}

.banner:has(button) {
display: flex;
justify-content: space-between;
gap: var(--space-s);
text-align: revert;
}

See the Pen

Flex метки с дочерними элементами input

Это связано с тем, что мне нравится следующий шаблон для меток. Потому что я люблю, чтобы они были inline элементами, но поля формы, которые следуют за ними, должны переноситься на новую строку.

label::after {
content: "\A";
white-space: pre;
}

Однако для меток, содержащих поля ввода, такие как чекбоксы и радио, желательно отображать их в виде макетов flexbox. Исторически это требовало добавления класса (или нескольких в кодовых базах ASS), но я обновил глобальные стили, чтобы использовать их вместо этого.

label:has(input) {
display: flex;
align-items: flex-start;
gap: var(--space-s);
}

Примечание. Причина, по которой я ищу только input, заключается в том, что я никогда не помещаю текстовые поля внутри меток. Если вы делаете так, то вам следует обновить селектор: label:has(:is(input[type="checkbox"], input[type="radio"])).

See the Pen

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

Это очень быстро и просто. Если у вас есть элемент с id, вы можете вызвать его :target состояние, добавив его id к URL с #, например, так: https://example.com/#my-element.

Исторически сложилось так, что вы не могли применять стили к родительскому элементу элемента, когда он является целевым, но теперь вы можете это сделать с помощью :has().

section:has(:target) {
background: var(--color-light-shade);
border: 2px solid var(--color-primary);
}

See the Pen

Затемнение соседних элементов при наведении курсора на элемент

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

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

Но с :has() это больше не так!

.tiles:has(:hover) .tile:not(:hover) {
opacity: 70%;
}

Прелесть этого селектора в том, что он чётко показывает, что происходит.

See the Pen

Подведение итогов

Да, в этой статье нет ничего сложного или навороченного, но я хотел показать несколько удобных реальных способов использования :has(). Если вы действительно хотите разобраться в :has(), настоятельно рекомендую ознакомиться с интерактивным руководством Ахмада. Это просто фантастика!

P.S. И последний маленький трюк. На сайте Piccalilli абзацы в блоке .post ограничены max-width: 60ch;. Однако это не идеально для примеров, так что...

.post p:has(code-pen) {
max-width: unset;
}

Дополнительные материалы

Предыдущая Статья

Ошибки в составлении SQL запросов и как их избежать

Следующая Статья

Доводы против самозакрывающихся тегов в HTML