I livelli a cascata saranno in arrivo per il tuo browser

I livelli in cascata (la @layerregola CSS) saranno disponibili in Chromium 99, Firefox 97 e Safari 15.4 beta. Consentono un controllo più esplicito dei file CSS per evitare conflitti di specificità degli stili. Questo è particolarmente utile per codebase di grandi dimensioni, sistemi di progettazione e per la gestione di stili di terze parti nelle applicazioni.

La stratificazione del CSS in modo chiaro impedisce l'override di stili inaspettato e favorisce una migliore architettura CSS.

Specificità CSS e gerarchia

La specificità CSS indica in che modo il CSS decide quali stili applicare a quali elementi. I diversi selettori che puoi utilizzare determinano la specificità di qualsiasi regola di stile. Ad esempio, gli elementi sono meno specifici delle classi o degli attributi, che a loro volta sono meno specifici degli ID. Si tratta di un aspetto fondamentale dell'apprendimento del CSS.

Le persone ricorrono a convenzioni di denominazione CSS come BEM per evitare di eseguire l'override della specificità in modo involontario. Se assegni a tutto un'unica classe, tutto viene inserito nello stesso piano di specificità. Tuttavia, non è sempre possibile mantenere stili così organizzati, soprattutto quando si utilizzano sistemi di design e codice di terze parti.

Visualizzazione BEM di una scheda con classi
Un esempio illustrato di denominazione BEM da keepinguptodate.com.

Lo scopo dei livelli a cascata è risolvere questo problema. Introducono un nuovo livello alla cascata CSS. Con gli stili a livelli, la precedenza di un livello supera sempre la specificità di un selettore.

Ad esempio, il selettore .post a.link ha una specificità maggiore di .card a. Se stai cercando di applicare uno stile a un link all'interno di una scheda in un post, verrà applicato il selettore più specifico.

Utilizzando @layer, puoi specificare in modo più esplicito la specificità dello stile di ciascuno e assicurarti che gli stili del link della scheda sostituiscano quelli del link del post, anche se la specificità potrebbe essere numericamente inferiore se tutti i CSS fossero sullo stesso piano. Questo accade a causa della precedenza in cascata. Gli stili a livelli creano nuovi "piani" in cascata.

Illustrazione della demo del progetto di suddivisione dell'interfaccia utente

@layer in azione

Demo che mostra i colori dei link con le importazioni
Guarda la demo su Codepen.

Questo esempio mostra la potenza dei livelli in cascata, utilizzando @layer. Vengono visualizzati diversi link: alcuni senza nomi di classi aggiuntivi, uno con una classe .link e uno con una classe .pink. Il CSS aggiunge quindi tre livelli: base, typography e utilities come segue:

@layer base {
  a {
    font-weight: 800;
    color: red; /* ignored */
  }

  .link {
    color: blue; /* ignored */
  }
}

@layer typography {
  a {
    color: green; /* styles *all* links */
  }
}

@layer utilities {
  .pink {
    color: hotpink;  /* styles *all* .pink's */
  }
}

Alla fine, tutti i link sono verdi o rosa. Questo perché, sebbene .link abbia una specificità a livello di selettore superiore a a, a ha uno stile di colore in @layer con una precedenza più alta. a { color: green } sostituisce .link { color: blue } quando la regola verde si trova in un livello successivo alla regola blu.

La precedenza del livello ha la precedenza sulla specificità dell'elemento.

Organizzare i livelli

Puoi organizzare i livelli direttamente nella pagina, come mostrato sopra, oppure nella parte superiore di un file.

L'ordine dei livelli viene stabilito la prima volta che il nome di ogni livello viene visualizzato nel codice.

Ciò significa che, se aggiungi quanto segue all'inizio del file, tutti i link verranno visualizzati in rosso, mentre il link con la classe .link verrà visualizzato in blu:

@layer utilities, typography, base;

Questo perché l'ordine dei livelli è ora invertito, con le utilità prima e la base per ultima. Di conseguenza, le regole di stile nel livello base avranno sempre una specificità maggiore rispetto alle regole di stile nel livello di tipografia. Non saranno più link verdi, ma rossi o blu.

Screenshot del progetto Codepen
Guarda la demo su Codepen.

Organizzazione delle importazioni

Un altro modo per utilizzare @layer è con i file di importazione. Puoi farlo direttamente quando importi gli stili, utilizzando una funzione layer() come nell'esempio seguente:

/* Base */
@import '../styles/base/normalize.css' layer(base); /* normalize or rest file */
@import '../styles/base/base.css' layer(base); /* body and base styles */
@import '../styles/base/theme.css' layer(theme); /* theme variables */
@import '../styles/base/typography.css' layer(theme); /* theme typography */
@import '../styles/base/utilities.css' layer(utilities); /* base utilities */

/* Layouts */
@import '../styles/components/post.css' layer(layouts); /* post layout */

/* Components */
@import '../styles/components/cards.css' layer(components); /* imports card */
@import '../styles/components/footer.css' layer(components); /* footer component */

Lo snippet di codice riportato sopra ha tre livelli: base, layouts e components. I file di normalizzazione, tema e tipografia in base, un file post in layouts e cards e footer entrambi in components. Al momento dell'importazione del file, gli strati vengono istantaneamente creati utilizzando la funzione layer. Un approccio alternativo consiste nell'organizzare i livelli nella parte superiore del file, dichiarandoli prima di qualsiasi importazione:

@layer base,
       theme,
       layouts,
       components,
       utilities;

Ora l'ordine in cui @import gli stili non ha più importanza per l'ordine dei livelli, poiché è già stabilito alla prima istanza del nome del livello. Una preoccupazione in meno. Puoi comunque impostare i file importati su livelli specifici, ma l'ordine è già stabilito.

Screenshot del progetto Codepen
Esplora il progetto su Codepen.

Livelli e struttura a cascata

Facciamo un passo indietro e vediamo dove vengono utilizzati i livelli rispetto alla struttura a cascata più ampia:

Illustrazione a cascata

L'ordine di precedenza è il seguente:

  • User agent normale (priorità più bassa)
  • Utente locale @livello
  • Utente locale normale
  • Autore @layers
  • Autore normale
  • Autore !important
  • Author @layer !important
  • Utente locale !important
  • User Agent !important** (priorità massima)

Potresti notare che gli stili @layer !important sono invertiti. Invece di essere meno specifici degli stili non a livelli (normali), hanno una priorità maggiore. Questo è dovuto al funzionamento di !important nella struttura a cascata: interrompe la normale applicazione a cascata degli stili e inverte la normale specificità a livello di livello (precedenza).

Livelli nidificati

I livelli possono anche essere nidificati all'interno di altri livelli. L'esempio seguente è tratto dalla spiegazione dei livelli a cascata di Miriam Suzanne:

@layer default {
  p { max-width: 70ch; }
}

@layer framework {
  @layer default {
    p { margin-block: 0.75em; }
  }

  p { margin-bottom: 1em; }
}

Nello snippet di codice riportato sopra, puoi accedere a framework.default utilizzando un . come indicatore del livello default nidificato in framework. Puoi anche scrivere questa espressione in un formato più abbreviato:

@layer framework.default {
  p { margin-block: 0.75em }
}

I livelli e l'ordine risultanti sono:

  • predefinita
  • framework.default
  • framework senza livelli
  • senza livelli

Aspetti a cui prestare attenzione

I livelli in cascata possono essere molto utili se li utilizzi correttamente, ma possono anche creare ulteriore confusione e risultati inaspettati. Quando utilizzi gli strati a cascata, tieni presente quanto segue:

Regola 1: non utilizzare @layer per l'ambito

I livelli a cascata non risolvono il problema dell'ambito. Se hai un file CSS con un @layer, ad esempio card.css, e vuoi applicare uno stile a tutti i link all'interno della scheda, non scrivere stili come:

a {
  
}

In questo modo, tutti i tag a nel file verranno sostituiti. È comunque importante definire l'ambito degli stili in modo appropriato:

.card a {
  
}

Regola 2: i livelli in cascata sono ordinati dietro il CSS non a livelli

È importante notare che un file CSS a livelli non sostituirà il CSS non a livelli. Si è trattato di una decisione intenzionale per semplificare l'introduzione dei livelli in un modo più sensato per lavorare con la base di codice esistente. L'utilizzo di un file reset.css, ad esempio, è un buon punto di partenza e un caso d'uso per i livelli a cascata.

Regola 3: !important inverte la specificità della cascata

Sebbene in generale gli stili a livelli siano meno specifici di quelli non a livelli, l'utilizzo di !important inverte questa situazione. In un livello, le dichiarazioni con la regola !important sono più specifiche rispetto agli stili non a livelli.

In questo caso, gli stili !important invertono la loro specificità. Il diagramma riportato sopra mostra questo come riferimento: author @layers ha una precedenza inferiore rispetto ad author normal, che ha una precedenza inferiore rispetto ad author !important, che ha una precedenza inferiore rispetto ad author @layer !important.

Se hai più livelli, il primo livello con !important avrà la precedenza su !important e sarà lo stile più specifico.

Regola 4: comprendi i punti di inserimento

Poiché l'ordine degli strati viene stabilito la prima volta che il nome di ogni livello viene visualizzato nel codice, se inserisci una dichiarazione @layer dopo aver importato e impostato i layer() o dopo un'istruzione @layer diversa, questa può essere ignorata. A differenza del CSS, in cui la regola di stile più in basso nella pagina viene applicata per i livelli a cascata, l'ordine viene stabilito alla prima occorrenza.

Può trovarsi in un elenco, in un blocco di livello o in un'importazione. Se inserisci @layer dopo un elenco di importazione con layer(), non succederà nulla. Se lo inserisci nella parte superiore del file, imposterai l'ordine dei livelli e potrai vedere chiaramente i livelli all'interno dell'architettura.

Regola 5: fai attenzione alla specificità

Con i livelli in cascata, un selettore meno specifico (ad es. a) sostituirà un selettore più specifico (ad es. .link) se si trova in un livello più specifico. Considera quanto segue:

a in layer(components) sostituirà .pink in layer(utilities) se: è stato specificato @layer utilities, components. Sebbene sia una parte intenzionale dell'API, potrebbe essere fonte di confusione e frustrazione se non te lo aspetti.

Pertanto, se scrivi classi di utilità, includile sempre come livello di ordine superiore rispetto ai componenti con cui intendi sostituirle. Potresti pensare: "Ho appena aggiunto questa classe .pink per cambiare il colore, ma non viene applicata".

Scopri di più sui livelli in cascata

Per saperne di più sui livelli in cascata, puoi anche consultare queste risorse: