use e forward, come cambia SASS e i nostri progetti
CssNon c'è dubbio che Sass sia uno strumento indispensabile per chiunque si occupi di sviluppo frontend e uno dei punti di forza è quello di permetterci di suddividere il progetto in vari file, con la logica che preferiamo, referenziandoli tra di loro usando la direttiva @import
, per poi compilarli in un unico file di output.
Come specificato anche dalla documentazione ufficiale però @import
non è necessariamente il metodo appropriato per includere un file (chiaramente era anche l'unico fino all'introduzione di @use
e @forward
), tanto che dal 1 Ottobre 2021 è stata avviata la prima fase di deprecazione di @import
che si concluderà con il drop definitivo il prossimo 1 Ottobre 2022 (questo riguarda le librerie Dart Sass e LibSass).
In sostituzione di @import
avremo ben due nuove direttive, @use
e @forward
, che rendono più strutturato il meccanismo di importazione di file e introducono diverse novità.
Differenze tra use e forward
Entrambe le direttive in qualche modo "importano" un file ma in modi diversi, è importante quindi capire bene come e quando usarle.
Use
Sulle prime @use
mi era sembrato potesse essere un rimpiazzo di @import
tanto che la prima cosa che ho fatto è stata quella di sostituire gli @import
del mio progetto con @use
salvo rendermi conto molto rapidamente che non funzionava proprio allo stesso modo.
Facciamo un esempio molto semplice; abbiamo un file con alcune regole tipografiche e vogliamo importarlo nel file principale chiamato style.scss, quello che andremo a scrivere sarà:
@use "typography";
Il risultato compilato in style.css sarà qualcosa del genere:
h1 { font-size: 48px } h2 { font-size: 32px } ...
Questo è quello che sarebbe successo anche con @import
giusto? In questo caso specifico si, non ci sono differenze, ma facciamo un esempio diverso; sempre nello stesso file di tipografia andiamo a mettere anche un mixin (che con grande fantasia chiameremo appunto mixin) e una variabile che cercheremo poi di riutilizzare nel file style.scss all’interno di una nuova regola:
@use "typography"; .selettore {
@include mixin;
color: $variabile;
}
Se proviamo a compilare questo file il sistema genererà un errore, questo perché @use
introduce il concetto di <namespace>
che vedremo più avanti essere molto importante.
Nell'esempio che abbiamo appena visto, il <namespace>
viene assegnato automaticamente ed è corrispondente al nome del file, quindi dovremo richiamare mixin o variabili in questo modo:
@use "typography"; .selettore {
@include typography.mixin;
color: typography.$variabile;
}
Questo è chiaramente un esempio molto semplice (e anche poco credibile) ma dovrebbe aiutarvi a farvi un'idea di come funziona @use
.
Forward
La direttiva @forward
a sua volta ci permette di importare un file, ma funziona in modo leggermente diverso rispetto a @use
. Prendiamo l'esempio precedente e sostituiamo @use
con @forward
sempre nel nostro file style.scss:
@forward "typography";
Questo verrà compilato senza problemi come anche nel primo esempio di @use
ma se proviamo a richiamare il mixin o la variabile il compilatore genererà un errore.
Questo perché @forward
si occupa diciamo di "trasportare" il contenuto di un file ma non renderlo "interattivo", possiamo immaginare come se @use
fosse un @import
"attivo" e @forward
"passivo".
Anche @forward
a sua volta supporta il <namespace>
e può chiaramente essere usato in combinata con @use
come vedremo più avanti.
L'importanza del namespace
In PHP come anche in altri linguaggi il <namespace>
è abbastanza comune ma in Sass è una "novità" (tralasciando che è in giro da metà 2019).
Per chi è magari alle prime armi magari potrebbe non essere così ovvio ma avere la possibilità di utilizzare un <namespace>
ci permette di rendere più sicuro il nostro codice e sopratutto riutilizzabile con più facilità.
Facciamo qualche esempio per rendere più chiara l'utilità del <namespace>
; immaginiamo di avere un file di mixins che vogliamo importare nel file style.scss per poterli applicare, con il precedente sistema @import
avremmo scritto una cosa del genere:
@import "mixins"; .selettore {
@include nome-mixin;
}
Questo è perfettamente valido, ma ci espone ad alcuni problemi;
- essendo disponibili globalmente è necessario aggiungere un prefisso ai nostri mixin o funzioni per evitare collisioni di nomi
- problemi di specificità di inclusione, in parole povere, se un altro file dichiara dopo il nostro un mixin con lo stesso nome andrà a rimpiazzare il precedente, questo come potrete immaginare rende abbastanza imprevedibile la gestione su progetti grandi.
Come ci aiuta quindi il <namespace>
?
Mi piace vederlo come una specie di categorizzazione, in pratica quello che dobbiamo fare è organizzare in modo logico i nostri mixin e funzioni per potergli associare un <namespace>
appropriato.
Prima abbiamo visto come il <namespace>
venga generato in automatico da Sass in funzione del nome del file, questo però può andar bene in casi molto semplici, ma se iniziamo ad utilizzare nomi più lunghi diventa tutto più scomodo, facciamo qualche esempio:
@use "utilities/typography"; // Il namespace generato sarà typography h1 { @include typography.h1 }
Più andiamo a complicare i nomi e più diventa verbosa la sintassi, diventando molto scomodo da scrivere, quello che possiamo fare quindi è creare un alias:
@use "utilities/typography" as t; // Il namespace è diventato t h1 { @include t.h1 }
Nel caso in cui non ci interessi utilizzare il <namespace>
(in alcuni contesti specifici potrebbe non essere indispensabile) ci viene incontro la wildcard * che ci permette in qualche modo di "annullare" il <namespace>
e dire a Sass di prendere la funzione o il mixin così come sono stati definiti, ricadendo chiaramente in tutti i problemi legati all'@import
che abbiamo visto poco più sopra:
@use "utilities/typography" as *; // Il namespace viene annullato h1 { @include h1 }
Come possiamo utilizzarli in un progetto?
Ora che abbiamo compreso i concetti base vediamo come possiamo utilizzare le nuove direttive in un progetto o quanto meno l’approccio che sto seguendo nei miei progetti.
Solitamente suddivido il progetto in tre parti, layout, componenti e utilities (come base di partenza, da adattare chiaramente alla complessità del progetto), sfruttando le convenzioni di Sass utilizzo un file _index.scss dentro ogni cartella incaricato di importare i vari file che si trovano all’interno della sua cartella (utilizzando @forward
) per renderli disponibili nel file principale, solitamente style.scss.
Una struttura di esempio dei file di un progetto potrebbe essere qualcosa del genere:
// Struttura files di progetto style.scss _config.scss layout |-- _index.scss |-- blog.scss |-- post.scss components |-- _index.scss |-- componente.scss utilities |-- _index.scss |-- mixins.scss |-- functions.scss
Il file _index.scss della cartella layout:
// _index.scss di layout @forward "blog"; @forward "post"; …
Nel file style.scss ci basterà richiamare con @forward
il nome della cartella e Sass per convenzione andrà ad includere automaticamente il primo file index che trova al suo interno.
In testa al file invece utilizzando @use
andremo a caricare e rendere disponibile globalmente le variabili di configurazione presenti nel nostro file di configurazione in modo che i mixin o funzioni che devono leggere o operare sulla configurazione abbiano sempre disponibile il dato:
@use "_config"; @forward "layout"; @forward "components";
Infine abbiamo le utilities, che essendo tipicamente mixins o funzioni verranno richiamate utilizzando @use
all'interno dei singoli file di componenti o layout quando ci servono.
Moduli built-in di Sass
Abbiamo visto come il <namespace>
ci porti a "compartimentare" delle funzionalità, evitare conflitti e di riflesso creare dei "moduli" di funzioni o utilità potenzialmente riutilizzabili (creandoci quindi un nostro framework).
Parlando di moduli di funzionalità, Sass ne include diversi che sono:
- sass:color
- sass:list
- sass:map
- sass:math
- sass:meta
- sass:selector
- sass:string
I moduli che ritengo indispensabili sono Math e Map ma potete trovare maggiori dettagli su tutti i moduli nella documentazione ufficiale.
Conclusioni
Possiamo dire che la deprecazione di @import
di fatto sia stata una buona cosa, le nuove direttive ci permettono di creare progetti più solidi, ripagandoci rapidamente dello sforzo di adeguamento. Il mio consiglio è di iniziare a sperimentare con la nuova sintassi in un progetto nuovo, perché non sempre è possibile (ed economicamente sostenibile) aggiornare progetti già completati.
Altri articoli simili
Accessibilità e CSS, gestire gli oggetti in movimento
07.11.2019
Organizzare e gestire la tipografia con le mappe di SASS
06.11.2019
Usare le mappe per gestire font e colori con SASS
29.10.2019
Siamo pronti a fare a meno di un framework CSS?
17.10.2019
Contare gli elementi in pagina con CSS
14.08.2019
Variabili CSS, come e quando usarle
07.08.2019
Resettare o normalizzare il foglio stile?
16.07.2019