Двум конкурирующим синтаксисам нужна ваша помощь в определении того, какой из них следует отдать предпочтение кандидату на спецификацию.
Вложенность CSS — это удобное дополнение к синтаксису, позволяющее добавлять CSS-код внутри набора правил. Если вы использовали SCSS , Less или Stylus , то наверняка видели несколько разновидностей этого:
.nesting {
color: hotpink;
> .is {
color: rebeccapurple;
> .awesome {
color: deeppink;
}
}
}
Который после компиляции в обычный CSS препроцессором превращается в обычный CSS следующим образом:
.nesting {
color: hotpink;
}
.nesting > .is {
color: rebeccapurple;
}
.nesting > .is > .awesome {
color: deeppink;
}
Официальная версия CSS этого синтаксиса находится в стадии активного рассмотрения, и у нас возникло разделение мнений, поэтому мы хотели бы обратиться за помощью к сообществу, чтобы разрешить ситуацию. Остальная часть этой публикации будет посвящена вариантам синтаксиса, чтобы вы могли быть в курсе событий и пройти опрос в конце.
Почему точный пример вложения, показанный выше, не может быть синтаксисом вложения CSS?
Существует несколько причин, по которым самый популярный синтаксис вложенности нельзя использовать как есть:
Неоднозначный синтаксический анализ
Некоторые вложенные селекторы могут выглядеть точно так же, как свойства, и препроцессоры могут обрабатывать их и управлять ими во время сборки. Браузеры не обладают такими же возможностями, поэтому селекторы никогда не следует трактовать произвольно.Конфликты анализа препроцессора
Вложенность, реализованная в CSS, не должна нарушать работу препроцессоров или существующие процессы разработки. Это было бы разрушительно и неуважительно по отношению к этим экосистемам и сообществам.Ожидание
:is()
Для базовой вложенности не требуется:is(), но для более сложной вложенности требуется. См. пример №3 для краткого введения в списки селекторов и вложенность. Представьте, что список селекторов находится в середине селектора, а не в начале. В этом случае:is()требуется для группировки селекторов в середине другого селектора.
Обзор того, что мы сравниваем
Мы хотим добиться правильной вложенности CSS, и в этом ключе мы привлекаем сообщество. В следующих разделах будут описаны три возможные версии, которые мы рассматриваем. Затем мы рассмотрим несколько примеров использования для сравнения, а в конце проведём небольшой опрос, чтобы узнать, какой вариант вам больше нравится.
Вариант 1: @nest
Это текущий синтаксис, указанный в CSS Nesting 1. Он предлагает удобный способ вложения стилей, начиная новые вложенные селекторы с помощью & . Он также предлагает @nest для размещения контекста & в любом месте внутри нового селектора, например, когда вы добавляете не только подлежащие элементы. Он гибкий и минималистичный, но за счёт необходимости запоминать @nest или & в зависимости от вашего варианта использования.
Вариант 2: @nest ограничен
Это более строгий вариант, призванный сократить упомянутые затраты на запоминание двух методов вложенности. Этот ограниченный синтаксис допускает вложение только после @nest , поэтому отсутствует удобный шаблон «только добавление». Это устраняет неоднозначность выбора, создавая один легко запоминающийся способ вложения, но жертвует краткостью ради соблюдения правил.
Вариант 3: Скобки
Чтобы избежать двойного синтаксиса и лишних сложностей, характерных для предложений @nest , Мириам Сюзанна и Элика Этемад предложили альтернативный синтаксис , основанный на дополнительных фигурных скобках. Это обеспечивает ясность синтаксиса, добавляя всего два символа и не добавляя новых at-правил. Кроме того, это позволяет группировать вложенные правила по требуемому типу вложенности, упрощая работу с несколькими селекторами с одинаковой вложенностью.
Пример 1 — Прямое вложение
@гнездо
.foo {
color: #111;
& .bar {
color: #eee;
}
}
@nest всегда
.foo {
color: #111;
@nest & .bar {
color: #eee;
}
}
скобки
.foo {
color: #111;
{
& .bar {
color: #eee;
}
}
}
Эквивалентный CSS
.foo {
color: #111;
}
.foo .bar {
color: #eee;
}
Пример 2 — Сложное вложение
@гнездо
.foo {
color: blue;
&.bar {
color: red;
}
}
@nest всегда
.foo {
color: blue;
@nest &.bar {
color: red;
}
}
скобки
.foo {
color: blue;
{
&.bar {
color: red;
}
}
}
Эквивалентный CSS
.foo {
color: blue;
}
.foo.bar {
color: red;
}
Пример 3 — Списки селекторов и вложенность
@гнездо
.foo, .bar {
color: blue;
& + .baz,
&.qux {
color: red;
}
}
@nest всегда
.foo, .bar {
color: blue;
@nest & + .baz,
&.qux {
color: red;
}
}
скобки
.foo, .bar {
color: blue;
{
& + .baz,
&.qux {
color: red;
}
}
}
Эквивалентный CSS
.foo, .bar {
color: blue;
}
:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
color: red;
}
Пример 4 — Несколько уровней
@гнездо
figure {
margin: 0;
& > figcaption {
background: lightgray;
& > p {
font-size: .9rem;
}
}
}
@nest всегда
figure {
margin: 0;
@nest & > figcaption {
background: lightgray;
@nest & > p {
font-size: .9rem;
}
}
}
скобки
figure {
margin: 0;
{
& > figcaption {
background: lightgray;
{
& > p {
font-size: .9rem;
}
}
}
}
}
Эквивалентный CSS
figure {
margin: 0;
}
figure > figcaption {
background: hsl(0 0% 0% / 50%);
}
figure > figcaption > p {
font-size: .9rem;
}
Пример 5 — Вложение родительских элементов или смена темы
@гнездо
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
@nest всегда
.foo {
color: red;
@nest .parent & {
color: blue;
}
}
скобки
.foo {
color: red;
{
.parent & {
color: blue;
}
}
}
Эквивалентный CSS
.foo {
color: red;
}
.parent .foo {
color: blue;
}
Пример 6 — Смешивание прямого и родительского вложения
@гнездо
.foo {
color: blue;
@nest .bar & {
color: red;
&.baz {
color: green;
}
}
}
@nest всегда
.foo {
color: blue;
@nest .bar & {
color: red;
@nest &.baz {
color: green;
}
}
}
скобки
.foo {
color: blue;
{
.bar & {
color: red;
{
&.baz {
color: green;
}
}
}
}
}
Эквивалентный CSS
.foo {
color: blue;
}
.bar .foo {
color: red;
}
.bar .foo.baz {
color: green;
}
Пример 7 — Вложенность медиа-запросов
@гнездо
.foo {
display: grid;
@media (width => 30em) {
grid-auto-flow: column;
}
}
или явно / расширенно
.foo {
display: grid;
@media (width => 30em) {
& {
grid-auto-flow: column;
}
}
}
@nest всегда (всегда явный)
.foo {
display: grid;
@media (width => 30em) {
@nest & {
grid-auto-flow: column;
}
}
}
скобки
.foo {
display: grid;
@media (width => 30em) {
grid-auto-flow: column;
}
}
или явно / расширенно
.foo {
display: grid;
@media (width => 30em) {
& {
grid-auto-flow: column;
}
}
}
Эквивалентный CSS
.foo {
display: grid;
}
@media (width => 30em) {
.foo {
grid-auto-flow: column;
}
}
Пример 8 — Вложенные группы
@гнездо
fieldset {
border-radius: 10px;
&:focus-within {
border-color: hotpink;
}
& > legend {
font-size: .9em;
}
& > div {
& + div {
margin-block-start: 2ch;
}
& > label {
line-height: 1.5;
}
}
}
@nest всегда
fieldset {
border-radius: 10px;
@nest &:focus-within {
border-color: hotpink;
}
@nest & > legend {
font-size: .9em;
}
@nest & > div {
@nest & + div {
margin-block-start: 2ch;
}
@nest & > label {
line-height: 1.5;
}
}
}
скобки
fieldset {
border-radius: 10px;
{
&:focus-within {
border-color: hotpink;
}
}
> {
legend {
font-size: .9em;
}
div {
+ div {
margin-block-start: 2ch;
}
> label {
line-height: 1.5;
}
}}
}
}
Эквивалентный CSS
fieldset {
border-radius: 10px;
}
fieldset:focus-within {
border-color: hotpink;
}
fieldset > legend {
font-size: .9em;
}
fieldset > div + div {
margin-block-start: 2ch;
}
fieldset > div > label {
line-height: 1.5;
}
Пример 9 – Сложная вложенная группа «Кухонная мойка»
@гнездо
dialog {
border: none;
&::backdrop {
backdrop-filter: blur(25px);
}
& > form {
display: grid;
& > :is(header, footer) {
align-items: flex-start;
}
}
@nest html:has(&[open]) {
overflow: hidden;
}
}
@nest всегда
dialog {
border: none;
@nest &::backdrop {
backdrop-filter: blur(25px);
}
@nest & > form {
display: grid;
@nest & > :is(header, footer) {
align-items: flex-start;
}
}
@nest html:has(&[open]) {
overflow: hidden;
}
}
скобки
dialog {
border: none;
{
&::backdrop {
backdrop-filter: blur(25px);
}
& > form {
display: grid;
{
& > :is(header, footer) {
align-items: flex-start;
}
}
}
}
{
html:has(&[open]) {
overflow: hidden;
}
}
}
Эквивалентный CSS
dialog {
border: none;
}
dialog::backdrop {
backdrop-filter: blur(25px);
}
dialog > form {
display: grid;
}
dialog > form > :is(header, footer) {
align-items: flex-start;
}
html:has(dialog[open]) {
overflow: hidden;
}
Время голосовать
Надеемся, вы считаете это сравнение справедливым и представляете пример рассматриваемых нами вариантов синтаксиса. Внимательно изучите их и сообщите нам ниже, какой из них вам больше нравится. Мы ценим вашу помощь в развитии вложенности CSS до синтаксиса, который мы все поймём и полюбим!