Al contrario di altri preprocessori CSS, Sass mette a disposizione alcuni costrutti di controllo come i cicli e le istruzioni condizionali che consentono di generare delle regole in maniera dinamica o di includere nei fogli di stile certi blocchi di dichiarazioni a seconda che siano soddisfatte o meno determinate condizioni.
Istruzioni condizionali
In Sass è possibile inserire in una regola dei blocchi di dichiarazioni diversi in base a una o più condizioni. Per far ciò si usano la direttiva @if e le direttive ad essa associate @else if e @else. È però presente anche una funzione if() da cui partiamo in questa lezione mostrando un semplice esempio.
La funzione if()
La funzione if(condizione, valore-se-vero, valore-se-falso) restituisce uno di due possibili valori passati come argomenti a seconda che la condizione specificata come primo argomento sia vera o falsa. Vediamo un breve esempio.
/* file style.scss */
$width: 640px;
$threshold: 480px;
p {
font-size: if($width >= $threshold, 1.2em, 1em);
}
Nel frammento di codice riportato sopra assegniamo alla proprietà font-size il valore 1.2em dal momento che la condizione passata come primo argomento alla funzione if() è vera.
/* file style.css */
p {
font-size: 1.2em;
}
Le direttive @if, @else if e @else
Grazie alla direttiva @if è possibile includere un blocco di dichiarazioni in una regola solo se viene rispettata una determinata condizione come mostrato nell’esempio sottostante.
/* file style.scss */
$width: 640px;
$threshold: 480px;
p {
@if $width >= $threshold {
font-size: 1.2em;
width: 400px;
height: 300px;
}
}
La sintassi usata per la direttiva @if è quindi la seguente.
@if <condizione> {
<blocco-dichiarazioni>
}
E il file CSS generato conterrà il frammento di codice mostrato sotto.
/* file style.css */
p {
font-size: 1.2em;
width: 400px;
height: 300px;
}
Ovviamente possiamo annidare delle istruzioni if e, se necessario, è possibile utilizzare le due direttive @else if e @else insieme alla direttiva @if come mostrato nel seguente esempio.
/* file style.scss */
$width: 320px;
$threshold: 480px;
p {
@if $width > $threshold {
font-size: 1.2em;
width: 600px;
height: 300px;
}
@else if $width < $threshold {
font-size: 1em;
width: 100vw;
height: 300px;
} @else {
font-size: 1.2em;
width: 450px;
height: 300px;
}
}
Dal momento che la variabile $width è pari a 320px, verrà selezionato il secondo blocco di dichiarazioni e il file generato sarà il seguente.
/* file style.css */
p {
font-size: 1em;
width: 100vw;
height: 300px;
}
Nella condizione della direttiva @if è possibile usare vari operatori di confronto simili a quelli usati nei linguaggi di programmazione. Avremo quindi degli operatori di uguaglianza (== e !=), degli operatori relazionali (<, >, <=, >=) e degli operatori booleani (and, or, not).
/* file style.scss */
$width: 600px;
$threshold: 480px;
$ok: 1;
$foo: 0;
p {
@if $width > $threshold and $ok == 1 and not ($foo != 0) {
font-size: 1.2em;
width: 600px;
height: 300px;
}
}
Per cui il frammento di codice riportato sopra, genererà il seguente file CSS.
/* file style.css */
p {
font-size: 1.2em;
width: 600px;
height: 300px;
}
I cicli in Sass
Sass presenta diversi costrutti sintattici che permettono di scorrere una lista o eseguire delle istruzioni più volte in base a una determinata condizione. La direttiva più utile nel primo caso è @each, ma in generale se vogliamo effettuare delle operazioni per un certo numero di iterazioni è possibile utilizzare le direttive @for e @while.
Il ciclo @for
In Sass è possibile eseguire un ciclo for usando l’apposita direttiva. La sintassi è la seguente.
@for <variabile> from <inizio> through <fine> {
<blocco-dichiarazioni>
}
Vediamo anche in questo caso un esempio.
/* file style.scss */
[class^="box"] {
width: 50px;
height: 50px;
}
@for $i from 0 through 3 {
.box-#{$i} {
transform: translateX(100px * $i);
border-radius: 10px * $i;
background-color: rgba(18, 11, 51, 1 - (.33 * $i));
}
}
Il corrispettivo file CSS generato a partire dal frammento di codice riportato sopra, sarà il seguente.
/* file style.css */
[class^="box"] {
width: 50px;
height: 50px; }
.box-0 {
transform: translateX(0px);
border-radius: 0px;
background-color: #120b33;
}
.box-1 {
transform: translateX(100px);
border-radius: 10px;
background-color: rgba(18, 11, 51, 0.67);
}
.box-2 {
transform: translateX(200px);
border-radius: 20px;
background-color: rgba(18, 11, 51, 0.34);
}
.box-3 {
transform: translateX(300px);
border-radius: 30px;
background-color: rgba(18, 11, 51, 0.01);
}
All’interno del browser otterremo invece un risultato simile a quello mostrato nell’immagine sottostante.
Nell’esempio appena illustrato, abbiamo usato una delle due possibili sintassi del ciclo for. (@for <variabile> from <inizio> through <fine>). In questo caso viene eseguito un numero di iterazioni a partire dal valore di ‘inizio‘ fino al valore di ‘fine‘ (estremo incluso). La sintassi alternativa prevede l’uso della keyword to al posto di through.
@for <i> from <inizio> to <fine> {
<blocco-dichiarazioni>
}
Stavolta la variabile ‘i’ verrà incrementata ogni volta a partire dal valore ‘inizio‘ fino al valore ‘fine – 1‘ (escluso quindi l’estremo ‘fine‘).
La direttiva @each
La direttiva @each permette di scorrere una serie di elementi di una lista o accedere alle coppie ‘chiave: valore’ di una mappa. La sintassi in questo caso è quella mostrata sotto.
@each <var1[, var2, var3...]> in <lista o mappa> {
<blocco-istruzioni>
}
Iniziamo a vedere quindi un primo esempio in cui usiamo la direttiva @each per scorrere gli elementi di una lista.
/* file style.scss */
@each $color in (red, green, blue) {
.#{$color} {background-color: $color;}
}
/* file style.css */
.red {
background-color: red;
}
.green {
background-color: green;
}
.blue {
background-color: blue;
}
Se alla direttiva @each passiamo una lista contenente delle sottoliste, possiamo accedere ai valori presenti in quest’ultime utilizzando più variabili come mostrato nell’esempio sotto.
/* file style.scss */
@each $class, $color in (
(red, #e04848),
(green, #66cf62),
(blue, #2c2a80)
) {
.#{$class} {background-color: $color;}
}
/* file style.css */
.red {
background-color: #e04848;
}
.green {
background-color: #66cf62;
}
.blue {
background-color: #2c2a80;
}
Analizziamo ora un altro esempio in cui utilizziamo la direttiva @each per accedere alle chiavi e ai valori di una mappa. Modifichiamo leggermente il codice appena mostrato come riportato sotto.
/* file style.scss */
$map: (
red: #fa1818,
green: #9ae797,
blue: #3836b9
);
@each $class, $color in $map {
.button--#{$class} {background-color: $color;}
}
E generiamo quindi il file CSS corrispondente.
/* file style.css */
.button--red {
background-color: #fa1818;
}
.button--green {
background-color: #9ae797;
}
.button--blue {
background-color: #3836b9;
}
La direttiva @while
Infine, come la direttiva @for, anche la direttiva @while consente di eseguire una serie di istruzioni finché è vera una certa condizione. La sintassi è la seguente:
@while <condizione> {
<blocco-dichiarazioni>
}
Trasformiamo quindi l’esempio visto sopra per la direttiva @for usando in questo caso la direttiva @while
/* file style.scss */
$i: 0;
[class^="box"] {
width: 50px;
height: 50px;
}
@while $i <=3 {
.box-#{$i} {
transform: translateX(100px * $i);
border-radius: 10px * $i;
background-color: rgba(18, 11, 51, 1 - (.33 * $i));
}
$i: $i + 1;
}
Nell’esempio riportato sopra abbiamo provveduto ovviamente a incrementare il valore della variabile $i altrimenti il ciclo non sarebbe mai terminato.
Anche nella condizione del ciclo while possiamo usare gli stessi operatori booleani e di confronto visti in precedenza per la direttiva @if.
Conclusioni
In questa lezione abbiamo visto alcuni esempi in cui abbiamo utilizzato le istruzioni condizionali e i cicli per generare dei fogli di stile in maniera dinamica evitando di dover riscrivere più volte lo stesso gruppo di dichiarazioni e decidendo se assegnare determinate proprietà grazie alla direttiva @if. Nelle prossime lezioni illustreremo come utilizzare le regole annidate che costituiscono una delle funzionalità più utili e interessanti presenti in Sass e vedremo come organizzare il codice in più file attraverso la direttiva @import.