Введение
Если вы фронтенд-разработчик, работавший с препроцессором CSS, вы, вероятно, сталкивались или использовали функцию вложенности. Это популярная функция, и для меня она стала одной из тех, что побудила меня использовать препроцессор CSS.
В этом году поддержка вложенности CSS появилась во всех основных браузерах: Chrome, Firefox и Safari. Это ключевая функция CSS, упрощающая написание CSS-кода. В этой статье я расскажу о том, что я узнал о вложенности CSS, и поделюсь своими выводами, а также примерами использования.
Никаких предварительных условий нет, кроме вашего энтузиазма и сосредоточенности.
Вложенность в CSS — долгожданная функция для многих разработчиков. Раньше мы полагались на препроцессоры CSS, такие как Sass или Less. Позвольте мне кратко рассказать о них:
Рассмотрим следующий пример. У нас есть иконка, которая находится в селекторе .nav__item.
.nav__item {
.icon {
display: flex;
padding: 1rem;
}
}Приведённый выше код является допустимым кодом Sass. После компиляции в браузере он будет выглядеть следующим образом:
.nav__item .icon {
display: flex;
padding: 1rem;
}При использовании встроенной функции вложенности CSS тот же самый CSS будет работать как есть. На рисунке показано сравнение встроенной функции вложенности CSS и инструментов разработчика браузера.
Обратите внимание, как браузер отображает CSS почти так же, как он отображается в CSS.
Если бы этот CSS-код был скомпилирован в Sass, браузер отобразил бы его следующим образом:
Преимущества вложенности CSS
На мой взгляд, существуют веские причины, по которым вложенные CSS-стили полезны:
- CSS легче читать.
- Группировка стилей
- Ограничение определенных стилей
- Стилизация HTML-элементов, не имеющих классов или идентификаторов.
Правила вложенности CSS
Чтобы познакомить вас с вложенностью в CSS, я постараюсь привести наглядные примеры различных проблем в CSS и показать, как вложенность может помочь их решить.
Прежде всего, вам нужно узнать о символе амперсанда (&). Существует ряд ситуаций, когда этот символ необходим.
Вложенность элемента без класса или идентификатора
В этом примере элемент <a> Оформление осуществляется с помощью `.nav__item`. Использование тега `<head>` необязательно для корректной работы CSS.
.nav__item {
& a {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item a {
}Вы также можете отказаться от проставления галочки:
.nav__item {
a {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item a {
}Обратите внимание, что это недавнее обновление, и оно называется «Расслабленная вложенность CSS». Оно работает в последних версиях Chrome Canary и Safari Technology Preview. Ознакомьтесь с этой статьей об «Расслабленной вложенности» от Адама Аргила.
Вложенность элемента с классом
Рассмотрим тот же пример, что и раньше, но предположим, что элемент <a> В нём есть HTML-класс.
.nav__item {
.link {
display: block;
padding: 1.5rem 1rem;
}
}
/* Same as: */
.nav__item .link {
}Здесь нет необходимости использовать символ. Имя класса подойдет идеально.
Вложенные CSS-комбинаторы
Одним из преимуществ нативной вложенности CSS является использование комбинаторов. Давайте рассмотрим несколько примеров.
В приведенном ниже примере я хочу выбрать любой элемент с классом .nav__item, которому предшествует другой элемент с тем же классом. Для этой цели я использовал селектор смежных элементов.
В стандартной CSS-вложенности мы можем использовать символ амперсанда, чтобы имитировать его. Обратите внимание, что я повторил его дважды.
.nav__item {
& + & {
border-left: 2px solid;
}
}
Волшебство происходит во второй итерации амперсанда. Здесь браузер понимает, что я хочу использовать селектор соседнего элемента. Позвольте мне показать вам рисунок, демонстрирующий это:
Еще один пример вложенности — это комбинатор дочерних элементов. Он может выбирать непосредственного потомка элемента.
.nav__item {
> a {
padding: 1rem;
}
}Символ амперсанда
.nav__item {
& a {
color: blue;
}
}Это было необходимо в первоначальной спецификации вложенности CSS. В Safari TP 179+ и Chrome Canary 120 амперсанд больше не требуется для вложенных элементов.
В результате работает следующее:
.nav__item {
a {
color: blue;
}
}Единственная проблема заключается в том, что вам придётся вернуться к предыдущей версии спецификации, которая должна включать разметку и соответствующие ей документы.
Вложенность с примером: Active, Focus, Hover
:active, :focus и :hover — это псевдоклассы CSS, которые активируются действиями пользователя.
С помощью вложенности CSS мы можем вкладывать их все одновременно, чтобы избежать дублирования кода. Возьмем в качестве примера :hover:
button {
&:hover {
background-color: var(--bg-color);
}
&:focus {
outline: solid 2px;
}
}Разница при использовании препроцессора для вложенности заключается в том, что браузер отображает её следующим образом:
button:hover {
background-color: var(--bg-color);
}
button:focus {
outline: solid 2px;
}Давайте посмотрим, как вложенность CSS отображается в Chrome, Safari и Firefox.
У меня есть несколько соображений по поводу использования инструментов разработчика для вложенных CSS-стилей, и я рассмотрю их позже в статье.
Пример вложенной структуры: публикация контента
Один из первых примеров тестирования вложенных CSS-стилей — это оформление основного содержимого публикации. Представьте себе статью с заголовками, текстом, изображениями, цитатами и многим другим.
Заголовки
Мы обычно оформляем заголовки следующим образом:
.post-content h1,
.post-content h2,
.post-content h3,
.post-content h4 {
/* styles here */
}С помощью вложенных CSS-стилей это проще:
.post-content {
h1,
h2,
h3,
h4 {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}То же самое можно сделать и с помощью селектора :is().
.post-content {
:is(h1, h2, h3, h4) {
color: var(--heading-color);
font-weight: var(--heading-font-bold);
margin-bottom: var(--size-2);
}
}Элемент абзаца
Распространенный пример — оформление ссылки, находящейся внутри абзаца. В таком случае вложенность CSS-стилей работает отлично.
.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
}
}
}Для отображения ссылки также может потребоваться эффект наведения курсора или фокусировки.
.post-content {
& p {
color: var(--color-black);
& a {
font-weight: bold;
text-decoration: underline;
&:hover {
/* hover styles */
}
}
}
}Мы также можем вкладывать медиа-запросы друг в друга.
.post-content {
& p {
/* base styles */
@media (min-width: 400px) {
/* do something */
}
}
}В некоторых случаях CMS может быть элементом <p> Оберните его в другой элемент, и в целях стиля его следует использовать только для прямых элементов. <p> Создайте стиль.
.post-content {
/* Select the direct <p> elements */
> p {
/* base styles */
}
}Блочная цитата
В этом примере цитата получает собственный стиль и элемент <p> Внутри цитаты выберите параметр, чтобы сбросить нижнее поле до нуля.
.post-content {
& blockquote {
/* custom quote styling */
& p {
margin-bottom: 0;
}
}
}Форма столба
Форма для отправки сообщения содержит изображение и
В моем примере, если
.post-content {
& figure {
& img {
/* the figure's image styles */
}
/* changes to the <figure> container, if it has a figcaption element */
&:has(figcaption) {
display: flex;
align-items: start;
}
& figcaption {
/* caption styling */
}
}
}Список сообщений
Мне нужно добавить рамку ко всем элементам списка, кроме последнего. Для этого я использовал селектор :not().
.post-content {
li {
&:not(:last-child) {
border-bottom: 1px solid;
}
}
}Чтобы использовать `:not()`, необходимо добавить перед ним амперсанд.
Настраиваемое расстояние для заголовков
Следующее расстояние должно быть <h3> и <h4> Я уменьшу количество символов, если за одним из них последует фрагмент кода.
.post-content {
& h3 + [class*="language-"],
& h4 + [class*="language-"] {
margin-top: 0.5rem;
}
}Как вы убедились на этом практическом примере, использование вложенности CSS очень просто, особенно если вы знакомы с препроцессорами CSS.
Вложенность на примере: компонент Card
Я покажу простой компонент карточки, который использует вложенность CSS для достижения желаемых стилей.
Предположим, что существует элемент `.card` со стилями по умолчанию или базовыми стилями. Я продемонстрирую использование вложенных CSS-стилей.
.card {
/* default card styles */
}
ЗАПРОСЫ ПО КОНТЕЙНЕРАМ ДЛЯ ГНЕЗДАНИИ
Если ширина контейнера превышает 400 пикселей, я хочу, чтобы карточка трансформировалась в гибкий контейнер.
.card {
/* default card styles */
/* if the container width is 400px or bigger */
@container card (min-width: 400px) {
display: flex;
}
}Оформление элемента абзаца
Я хочу использовать элемент абзаца следующим образом: <h3> Таким образом, я могу задать поля и отступы для элемента. <p> Добавлю. Если этого не будет, то и в пользовательском интерфейсе не будет дополнительного пространства.
.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
}Если ширина контейнера составляет 400 пикселей или более, элемент .card__content также должен быть преобразован в гибкий контейнер.
.card__content {
& h3 + p {
border-top: 1px solid #000;
padding-top: 0.5rem;
margin-top: 0.5rem;
}
@container card (min-width: 400px) {
display: flex;
flex-direction: column;
justify-content: center;
}
}Вложенность на примере: поле ввода формы
Распространенный случай — оформление заполнителя поля ввода. Проблема в том, что у каждого производителя браузеров свой префикс (ой, на дворе 2023 год).
Поскольку для префиксных стилей требуется двоеточие, необходимо использовать символ &, иначе стили не будут работать.
input {
--placeholder-color: #969696;
/* other styles */
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
&::-moz-placeholder {
color: var(--placeholder-color);
opacity: 1;
}
&:-moz-placeholder {
color: var(--placeholder-color);
}
}Возможно, вас интересует, в чем разница между использованием вложенных CSS-стилей и написанием префиксного стиля напрямую без них.
/********** Option 1: native nesting **********/
input {
&::-webkit-input-placeholder {
color: var(--placeholder-color);
}
}
/********** Option 2: without nesting **********/
input::-webkit-input-placeholder {
color: var(--placeholder-color);
}Между ними нет никакой разницы. Оба обладают одинаковыми свойствами (0, 1, 1).
Вложенность с примером: стилизация элемента через его родительский элемент.
Мы можем использовать вложенность CSS для изменения стилей дочернего элемента в зависимости от его местоположения. Например, если элемент `.button` находится внутри родительского элемента `.box`, он должен занимать всю ширину.
<div class="box">
<h2>Get access to all features</h2>
<p>Create an account now and get access to all exclusive features.</p>
<a href="/offer" class="button">Create an account</a>
</div>.button {
.box & {
width: 100%;
}
}
/* equivalent to */
.box .button {
}Ошибки, которые я обнаружил при изучении вложенности CSS.
Использование беззнакового глобального селектора
Допустим, у нас есть карточка, и мы хотим выделить все элементы внутри неё. С помощью CSS Native Nesting это должно сработать:
.card {
* {
/* styles here */
}
}Я заметил, что это не работает в Chrome Stable, но прекрасно функционирует в Chrome Canary 121, Safari 17.1 и Firefox 119.
Решение состоит в добавлении знака препинания.
.card {
& * {
/* styles here */
}
}Использование беззнаковых атрибутов данных
В данном случае выбор атрибута данных без галочки не дает ожидаемого результата.
.card {
[data-type="featured"] {
/* styles here */
}
}Я заметил, что это не работает в Chrome Stable, но прекрасно функционирует в Chrome Canary 121, Safari 17.1 и Firefox 119.
Чтобы это исправить, нужно добавить запятую:
.card {
&[data-type="featured"] {
/* styles here */
}
}Обе эти ошибки были исправлены в версии Chrome Canary, обеспечивающей более свободную вложенность CSS.
Определение поддержки вложенности CSS
Параметр `@supports` можно использовать для проверки поддержки вложенности CSS-стилей. В нашем случае мы хотим проверить, распознает ли браузер амперсанд.
@supports selector(&) {
.post-content {
& h2 {
/* styles here. */
}
}
}Другие варианты определения поддержки можно посмотреть в этом примере на Codepen от Bramus.
Сегодня я воспользуюсь плагином PostCSS nesting, который компилирует вложенный CSS в обычный CSS. Я удалю этот плагин, когда его использование станет безопасным.
Инструменты разработчика для UX-вложенности CSS
Мне не очень нравится текущий пользовательский интерфейс для вложенных CSS-кодов в инструментах разработчика браузера.
Я работал над отдельной статьей, в которой рассмотрел несколько предложений о том, как бы я хотел видеть вложенность CSS в инструментах разработчика.
Результат
Вложенность CSS — это важная функция, улучшающая способ написания CSS-кода. В настоящее время использование вложенности возможно, но следует быть осторожным с аудиторией, поскольку поддержка этого функционала пока относительно новая.
























