Guida alla scelta di una sintassi per la nidificazione CSS

Due sintassi concorrenti hanno bisogno del tuo aiuto per determinare quale deve essere promossa a un candidato di specifica.

Andrea Rossi
Adam Argyle
Miriam Suzanne
Miriam Suzanne

La nidificazione di CSS è un'aggiunta di sintassi di utilità che consente di aggiungere CSS all'interno di un set di regole. Se hai utilizzato SCSS, Meno o Stilo, sicuramente ne hai provati alcuni:

.nesting {
  color: hotpink;

  > .is {
    color: rebeccapurple;

    > .awesome {
      color: deeppink;
    }
  }
}

che, una volta compilato in CSS normale dal preprocessore, si trasforma in un normale CSS come il seguente:

.nesting {
  color: hotpink;
}

.nesting > .is {
  color: rebeccapurple;
}

.nesting > .is > .awesome {
  color: deeppink;
}

Stiamo valutando attentamente una versione CSS ufficiale di questa sintassi e abbiamo una suddivisione in preferenze che vorremmo utilizzare l'aiuto della community per rompere il legame. Il resto di questo post introdurrà le opzioni di sintassi per permetterti di rispondere a un sondaggio alla fine.

Perché l'esempio di nidificazione mostrato sopra non può essere la sintassi per la nidificazione CSS?

Esistono diversi motivi per cui la sintassi di nidificazione più diffusa non può essere utilizzata così com'è:

  1. Analisi ambigua
    Alcuni selettori nidificati possono assomigliare esattamente a proprietà e preprocessori sono in grado di risolverli e gestirli in fase di build. I motori dei browser non avranno le stesse affinità e i selettori non devono mai essere interpretati in modo libero.

  2. Conflitti di analisi del preprocessore
    Il metodo di nidificazione CSS non deve interrompere i preprocessori o i flussi di lavoro di nidificazione esistenti degli sviluppatori. Ciò comporterebbe problemi e non considerati in alcun modo per tali ecosistemi e comunità.

  3. In attesa di :is()
    La nidificazione di base non richiede :is(), al contrario la nidificazione più complessa. Vedi l'esempio n. 3 per una leggera introduzione agli elenchi di selettori e alla nidificazione. Immagina che l'elenco di selettori si trovi al centro di un selettore anziché all'inizio. In questi casi, è necessario :is() per raggruppare i selettori al centro di un altro selettore.

Panoramica dei confronti

Vogliamo fare in modo che si integrino correttamente i CSS e, con questo spirito, includiamo la community. Le seguenti sezioni aiuteranno a descrivere le tre possibili versioni che stiamo valutando. Esamineremo alcuni esempi di utilizzo per il confronto e al termine ci sarà un leggero sondaggio in cui ti verrà chiesto quale preferisci in generale.

Opzione 1: @nest

Questa è l'attuale sintassi specificata in Nesting CSS 1. Offre un modo comodo per nidificare gli stili aggiungendo l'avvio di nuovi selettori nidificati con &. Offre inoltre @nest per posizionare il contesto & in qualsiasi punto all'interno di un nuovo selettore, ad esempio quando non stai solo aggiungendo oggetti. È flessibile e minimo, ma a costo di dover ricordare @nest o &, a seconda del caso d'uso.

Opzione 2: @nest con limitazioni

Questa è un'alternativa più rigorosa, nel tentativo di ridurre la spesa menzionata per ricordare due metodi di nidificazione. Questa sintassi limitata consente solo la nidificazione dopo @nest, quindi non esiste un pattern di convenienza solo di aggiunta. Rimuovendo l'ambiguità della scelta, creando un modo facile da ricordare per nidificare, ma sacrificando la chiarezza a favore della convenzione.

Opzione 3: parentesi quadre

Per evitare la doppia sintassi o il disordine legato alle proposte @nest, Miriam Suzanne ed Elika Etemad hanno proposto una sintassi alternativa che si basa invece su parentesi graffe aggiuntive. Ciò fornisce chiarezza della sintassi, con solo due caratteri aggiuntivi e nessuna nuova regola at-rule. Consente inoltre di raggruppare le regole nidificate in base al tipo di nidificazione richiesto, in modo da semplificare più selettori nidificati in modo simile.

Esempio 1: nidificazione diretta

@nest

.foo {
  color: #111;

  & .bar {
    color: #eee;
  }
}

@nest sempre

.foo {
  color: #111;

  @nest & .bar {
    color: #eee;
  }
}

parentesi quadre

.foo {
  color: #111;

  {
    & .bar {
      color: #eee;
    }
  }
}

CSS equivalente

.foo {
  color: #111;
}

.foo .bar {
  color: #eee;
}

Esempio 2 - Nidificazione composta

@nest

.foo {
  color: blue;

  &.bar {
    color: red;
  }
}

@nest sempre

.foo {
  color: blue;

  @nest &.bar {
    color: red;
  }
}

parentesi quadre

.foo {
  color: blue;

  {
    &.bar {
      color: red;
    }
  }
}

CSS equivalente

.foo {
  color: blue;
}

.foo.bar {
  color: red;
}

Esempio 3: elenchi di selettori e nidificazione

@nest

.foo, .bar {
  color: blue;

  & + .baz,
  &.qux {
    color: red;
  }
}

@nest sempre

.foo, .bar {
  color: blue;

  @nest & + .baz,
  &.qux {
    color: red;
  }
}

parentesi quadre

.foo, .bar {
  color: blue;

  {
    & + .baz,
    &.qux {
      color: red;
    }
  }
}

CSS equivalente

.foo, .bar {
  color: blue;
}

:is(.foo, .bar) + .baz,
:is(.foo, .bar).qux {
  color: red;
}

Esempio 4 - Più livelli

@nest

figure {
  margin: 0;

  & > figcaption {
    background: lightgray;

    & > p {
      font-size: .9rem;
    }
  }
}

@nest sempre

figure {
  margin: 0;

  @nest & > figcaption {
    background: lightgray;

    @nest & > p {
      font-size: .9rem;
    }
  }
}

parentesi quadre

figure {
  margin: 0;

  {
    & > figcaption {
      background: lightgray;

      {
        & > p {
          font-size: .9rem;
        }
      }
    }
  }
}

CSS equivalente

figure {
  margin: 0;
}

figure > figcaption {
  background: hsl(0 0% 0% / 50%);
}

figure > figcaption > p {
  font-size: .9rem;
}

Esempio 5: nidificazione del genitore o modifica dell'oggetto

@nest

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

@nest sempre

.foo {
  color: red;

  @nest .parent & {
    color: blue;
  }
}

parentesi quadre

.foo {
  color: red;

  {
    .parent & {
      color: blue;
    }
  }
}

CSS equivalente

.foo {
  color: red;
}

.parent .foo {
  color: blue;
}

Esempio 6 - Combinazione diretta e nidificazione principale

@nest

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    &.baz {
      color: green;
    }
  }
}

@nest sempre

.foo {
  color: blue;

  @nest .bar & {
    color: red;

    @nest &.baz {
      color: green;
    }
  }
}

parentesi quadre

.foo {
  color: blue;

  {
    .bar & {
      color: red;

      {
        &.baz {
          color: green;
        }
      }
    }
  }
}

CSS equivalente

.foo {
  color: blue;
}

.bar .foo {
  color: red;
}

.bar .foo.baz {
  color: green;
}

Esempio 7: nidificazione di query supporti

@nest

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

o esplicitamente / esteso

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

@nest Always (è sempre esplicito)

.foo {
  display: grid;

  @media (width => 30em) {
    @nest & {
      grid-auto-flow: column;
    }
  }
}

parentesi quadre

.foo {
  display: grid;

  @media (width => 30em) {
    grid-auto-flow: column;
  }
}

o esplicitamente / esteso

.foo {
  display: grid;

  @media (width => 30em) {
    & {
      grid-auto-flow: column;
    }
  }
}

CSS equivalente

.foo {
  display: grid;
}

@media (width => 30em) {
  .foo {
    grid-auto-flow: column;
  }
}

Esempio 8 - Nidificare gruppi

@nest

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 sempre

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;
    }
  }
}

parentesi quadre

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 equivalente

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;
}

Esempio 9: gruppo di annidamento complesso "Lavello da cucina"

@nest

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 sempre

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;
  }
}

parentesi quadre

dialog {
  border: none;

  {
    &::backdrop {
      backdrop-filter: blur(25px);
    }

    & > form {
      display: grid;

      {
        & > :is(header, footer) {
          align-items: flex-start;
        }
      }
    }
  }

  {
    html:has(&[open]) {
      overflow: hidden;
    }
  }
}

CSS equivalente

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;
}

È ora di votare

Spero che questo sia stato un confronto equo e un esempio di opzioni di sintassi che stiamo valutando. Esaminali attentamente e facci sapere di seguito quale preferisci. Ti ringraziamo per averci aiutato a migliorare la nidificazione di CSS su una sintassi che tutti impareremo a conoscere e ad apprezzare.

Partecipa al sondaggio.