Moduli CSS e alternativa CSS vanilla con i blocchi @scope e il selettore :scope.

⏱ Tempo di lettura:

5 minuti

Nella gestione di progetti front-end complessi, i problemi di specificità e ridondanza nel CSS possono rapidamente diventare un incubo. In questo articolo vorrei condividere come l’uso dei moduli CSS e della nuova regola @scope (insieme al selettore :scope) possano semplificare la gestione degli stili, evitando conflitti e migliorando l’organizzazione del codice.

Vedremo quindi cosa sono e come si integrano i moduli CSS, come funzionano i blocchi @scope e il selettore :scope e infine una tabella comparativa per aiutarti a decidere.



TLDR;

I moduli CSS permettono di utilizzare un subset specifico di classi presenti in un componente, collegandolo univocamente ad esso. Attraverso l’associazione un identificativo alle classi compilate, vengono meno i problemi di conflitti di stile. Tuttavia è necessario tool di compilazione.

D’altra parte, se si vuole usare strumenti per i quali non è necessaria la compilazione, lo standard CSS gode dell’implementazione di nuove specifiche che permettono la creazione e l’assegnazione di stili associati ad uno scope.

Cosa sono i moduli CSS?

Inizio col dire che per usare i moduli CSS servono degli strumenti di build, quali ad esempio Webpack o Vite. Questo perché i fogli di stile verranno poi ricompilati in maniera tale che le classi siano associate in modo univoco alla pagina che le importa.

Ad esempio, poniamo di voler importare un modulo CSS in un componente React. Il primo passo che da fare è importare il foglio di stile tramite import:

import styles from './styles/component.module.css'

Nel file CSS inseriamo le nostre classi:

.quote{
  padding: 8px;
  background-color: ghostwhite;  
}

.cite{
  font-style: italic;
  font-size: .85rem;
}

Poi potremo accedere alle classi come oggetto:

import styles from './styles/component.module.css'

export default function Quote(){
  return (
  <div className={styles.quote}>
    <blockquote><p cite="">Lorem ipsum dolor sit amet</p></blockquote>
    <p className={styles.cite}><cite>Cicero</cite>, 45 BC</p>
  </>
)}

Cosa succede in fase di build?

Il compilatore rinomina automaticamente le classi per renderle univoche:

<div class="component__quote__s93j">
  <blockquote>
  <p cite="">Lorem ipsum dolor sit amet</p>
  </blockquote>
  <p class="component__cite__r23k"><cite>Cicero</cite>, 45 BC</p>
</div>

E il CSS risultante:

.component__quote__s93j{
  padding: 8px;
  background-color: ghostwhite;  
}

.component__cite__r23k{

 font-style: italic;
  font-size: .85rem;
}

La modifica del nome della classe con un identificativo univoco è ciò che permette di isolare gli stili in base al contesto.

In questo modo, se nei fogli stile importarti nella pagina è già presente una classe analoga, non ci saranno problemi di override degli stili. Inoltre solo le classi usate nel componente verrano poi compilate, con un guuadagno in termini di velocità.

Blocco @scope e selettore :scope

Nel caso vi stiate chiedendo se ci sono funzioni native che permettono di isolare le classi in funzione del contesto, la risposta è si! Ma… come accade spesso dobbiamo fare i conti con il supporto dei browser, non sempre allo stesso livello e non sempre completo. Vediamo insieme il funzionamento.

Il funzionamento è molto semplice. Con la at rule @scope si può definire un’area all’interno del nostro markup entro il quale i nostri stili avranno effetto, senza intaccare gli elementi al di fuori. Il selettore :scope ci permetterà di stilare l’elemento padre.

Ecco un prova pratica su Codepen. Il markup è molto semplice, ci sono due elementi <nav> in posizioni diverse. I link del menu dentro <header> vogliamo mantenerli con lo stile globale, mentre quelli dentro l’<aside> con la classe navigation devono avere un colore diverso.

Nel dettaglio @scope server per designare uno scope e definirne l’ambito di applicazione:

/* @scope (scope) to (limite) */
@scope (.navigation) to (nav)

Nel nostro esempio di prima, lo scope è all’interno della classe .navigation e il limite di applicazione e dentro <nav>. Potresti chiederti: perché non usare semplicemente un selettore di classe?

La risposta in questo caso è la stessa per i moduli CSS: evitare la propagazione involontaria degli stili. E ovviamente migliorare la gestione degli stili in progetti di grosse dimensioni, con molte classi che vanno a nidificarsi e diventano inevitabilmente difficili da gestire.

Supporto dei browser

Come spiegavo in precedenza, ad oggi, il suppoto lato browser è limitato. Di seguito i link verso caniuse.com per @scope e :scope.

Moduli CSS e CSS vanilla a confronto

Veniamo quindi alla tabella in cui proviamo a mettere a confronto le due metodologie per capire dove meglio di adattano. Le caratteristiche che andremo a confrontare sono:

  • L’isolamento delle classi.
  • La compatibilità secondo Can I Use
  • La leggibilità del codice
  • L’organizzazione
  • L’efficienza di runtime
  • L’utilizzo pratico
  • La specificità
  • L’adozione
CaratteristicaModuli CSSBlocchi @scope con :scope
IsolamentoAutomatico: le classi sono localizzate al componente e non influenzano il DOM globale.Manuale: è necessario definire esplicitamente il blocco di isolamento
CompatibilitàAmpiamente supportato nei progetti React, Next.js e simili.Supporto sperimentale nei browser, richiede polyfill per l’uso pratico.
Leggibilità del codiceNomi delle classi generati automaticamente, risultano meno descrittivi.Più leggibile, dato che le classi restano definite in modo naturale.
OrganizzazioneFile dedicati per componente.Scoping tramite blocchi inline o esterni.
Efficienza di runtimePre-compilato durante il build (es. Webpack).Runtime nei browser, potrebbe essere più lento.
Utilizzo praticoRichiede configurazioni con strumenti come Webpack o Vite.Può essere usato direttamente nel CSS senza strumenti di build.
SpecificitàRisolve automaticamente i problemi di specificità e conflitti.I conflitti devono essere gestiti con attenzione manuale.
AdozioneMolto diffuso nei progetti moderni.Relativamente nuovo e poco utilizzato al momento.
In tabella appare evidente che ad oggi la soluzione offerta dai moduli CSS è quella maggiormente compatibile, a causa della mancanza di supporto nei browser delle soluzioni native. Inoltre i moduli CSS offrono una migliore gestione dei conflitti e vengono direttamente correlate al blocco che utilizza gli stili, con un ampio supporto di framework e librerie.

Cosa ne pensate? Avete già avuto modo di sperimentare con il nuovo blocco @scope e la pseudo-classe :scope? Fatemi sapere nei commenti!

Tag

Commenti

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *