Вложенность — одна из основных причин использования препроцессора CSS, такого как Sass. Теперь эта функция появилась в стандартном браузерном CSS с похожим синтаксисом. Можете ли вы удалить зависимость препроцессора от вашей системы сборки?
Вложение CSS экономит время набора текста и может упростить чтение и поддержку синтаксиса. До сих пор вам приходилось вводить полные пути селектора следующим образом:
.parent1 .child1, .parent2 .child1 { color: red; } .parent1 .child2, .parent2 .child2 { color: green; } .parent1 .child2:hover, .parent2 .child2:hover { color: blue; }
Теперь вы можете вкладывать дочерние селекторы в их родительские, например:
.parent1, .parent2 { .child1 { color: red; } .child2 { color: green; &:hover { color: blue; } } }
Вы можете вкладывать селекторы так глубоко, как вам нравится, но будьте осторожны, если вы выходите за пределы двух или трех уровней. Технических ограничений на глубину вложенности нет, но это может затруднить чтение кода, а результирующий CSS может стать излишне подробным.
До апреля 2023 года ни один браузер не понимал вложенный синтаксис CSS. Вам потребовался этап сборки с препроцессором CSS, таким как Sass, Less или PostCSS, чтобы преобразовать вложенный код в обычный синтаксис полного селектора. Теперь вложение появилось в Chrome 112+ и Safari 16.5+, а поддержка Firefox появится позже в 2023 году (в версии 115 она доступна с флагом функции).
Можете ли вы отказаться от своего препроцессора в пользу нативной вложенности? Как обычно… это зависит. Родной синтаксис вложенности развился за последние пару лет. Внешне он похож на Sass, что понравится большинству веб-разработчиков, но не ожидайте, что весь код SCSS будет работать так, как вы ожидаете.
Собственные правила вложения CSS
Вы можете вложить любой селектор в другой, но он должен начинаться с символа, такого как &
, .
(для HTML class
), #
(для HTML id
), @
(для медиа-запроса), :
, ::
, *
, +
, ~
, >
или [
. Другими словами, это не может быть прямой ссылкой на элемент HTML. Этот код недействителен, и <p>
селектор не анализируется:
.parent1 { /* FAILS */ p { color: blue; } }
Самый простой способ исправить это — использовать амперсанд ( &), который ссылается на текущий селектор так же, как в Sass:
.parent1 { /* WORKS */ & p { color: blue; } }
В качестве альтернативы вы можете использовать один из них:
- p— но это будет стилизовать прямых потомков.parent1только
- :is(p)— но :is() использует специфику самого конкретного селектора
- :where(p)— но :where() имеет нулевую специфичность
Все они будут работать в этом простом примере, но вы можете столкнуться со специфическими проблемами позже с более сложными таблицами стилей.
Также & позволяет нацеливать псевдоэлементы и псевдоклассы на родительский селектор. Например:
p.my-element { &::after {} &:hover {} &:target {} }
Если вы не используете &, вы будете ориентироваться на все дочерние элементы селектора, а не p.my-elementна него самого. (То же самое произойдет в Sass.)
Обратите внимание, что вы можете использовать в &любом месте селектора. Например:
.child1 { .parent3 & { color: red; } }
Это переводится в следующий невложенный синтаксис:
.parent3 .child1 { color: red; }
Вы даже можете использовать несколько &символов в селекторе:
ul { & li & { color: blue; } }
Это будет нацелено на вложенные <ul>
элементы ( ul li ul
), но я бы не рекомендовал использовать это, если вы хотите сохранить свое здравомыслие!
Наконец, вы можете вкладывать медиа-запросы. Следующий код применяет cyanцвет к элементам абзаца — если ширина браузера не меньше 800px, когда они становятся purple:
p { color: cyan; @media (min-width: 800px) { color: purple; } }
Нативные ошибки вложения CSS
Нативная вложенность заключает родительские селекторы в :is(), и это может привести к различиям с выводом Sass.
Рассмотрим следующий вложенный код:
.parent1, #parent2 { .child1 {} }
Это фактически становится следующим при анализе в браузере:
:is(.parent1, #parent2) .child1 {}
Элемент.child1внутри.parent1имеет специфичность 101, потому что :is()использует специфичность своего наиболее специфичного селектора — в данном случае #parent2ID.
Sass компилирует тот же код в это:
.parent1 .child1, #parent2 .child1 { }
В этом случае.child1элемент внутри.parent1имеет специфичность 002, потому что он соответствует двум классам ( #parent2игнорируется). Его селектор менее специфичен, чем собственный вариант, и у него больше шансов быть переопределенным в каскаде.
Вы также можете столкнуться с более тонкой проблемой. Учти это:
.parent .child { .grandparent & {} }
Собственный эквивалент CSS:
.grandparent :is(.parent .child) {}
Это соответствует следующим неправильно упорядоченным элементам HTML:
<div class="parent"> <div class="grandparent"> <div class="child">MATCH</div> </div> </div>
MATCH становится стилизованным, потому что синтаксический анализатор CSS делает следующее:
- Он находит все элементы с классом, у childкоторого также есть предок parent— в любой точке иерархии DOM.
- Найдя элемент, содержащий MATCH, синтаксический анализатор проверяет, есть ли у него предок grandparent— опять же, в любой точке вверх по иерархии DOM. Он находит его и соответствующим образом стилизует элемент.
Это не относится к Sass, который компилируется в это:
.grandparent .parent .child {}
Приведенный выше HTML-код не оформлен, поскольку классы элементов не следуют строгому порядку grandparent, parentи child.
Наконец, Sass использует замену строк, поэтому объявления, подобные приведенным ниже, действительны и соответствуют любому элементу с классом outer-space:
.outer { &-space { color: black; } }
Собственный CSS игнорирует &-spaceселектор.
Вам все еще нужен препроцессор CSS?
В краткосрочной перспективе ваш существующий препроцессор CSS останется важным. Собственная вложенность не поддерживается в браузерах на основе Firefox или Chrome/Safari, которые не получали обновлений в течение нескольких месяцев.
Команда разработчиков Sass объявила, что они будут поддерживать нативное вложение CSS в.cssфайлы и выводить код как есть. Они продолжат компилировать вложенный SCSSкод, как и раньше, чтобы не нарушать существующую кодовую базу, но начнут выдавать :is()селекторы, когда глобальная поддержка браузеров достигнет 98%.
Я подозреваю, что препроцессоры, такие как плагины PostCSS, пока будут расширять вложенный код, но удалят эту функцию, поскольку поддержка браузеров станет более распространенной.
Конечно, есть и другие веские причины для использования препроцессора, например объединение частичных кодов в один файл и минимизация кода. Но если вложение — единственная функция, которая вам нужна, вы, безусловно, можете рассмотреть собственный CSS для небольших проектов.
Заключение
Вложение CSS — одна из самых полезных и практичных функций препроцессора. Производители браузеров усердно работали над созданием нативной версии CSS, которая была бы достаточно похожа, чтобы понравиться веб-разработчикам. Тем не менее, есть тонкие различия, и вы можете столкнуться с необычными проблемами специфичности с (чрезмерно) сложными селекторами, но лишь немногие кодовые базы потребуют радикального пересмотра.
Встроенная вложенность может заставить вас пересмотреть потребность в препроцессоре CSS, но она по-прежнему предлагает другие преимущества. Sass и подобные инструменты остаются неотъемлемой частью большинства наборов инструментов для разработчиков.