Finalmente i CSS3 ci propongono flex, un sistema di gestione dei layout potente e flessibile, con tante luci e qualche ombra…
Procediamo con ordine
Chiunque abbia un po’ di esperienza con i CSS, sa bene quali sono i limiti ed i problemi imposti dalla tecnica del floating. D’altra parte il floating non era stato pensato per la gestione dei layout, ovvero non come sistema per cambiare posizione agli elementi, ma come sistema per “rimpiazzare” l’attributo align degli elementi <img>.
Quando i CSS hanno consentito di abbandonare le tabelle per la gestione dei layout, il float è diventato un male necessario, in quanto non esisteva un meccanismo pensato per consentire ad un designer di “giocare” con i box, spostandoli a piacimento per creare layout diversi, a prescindere dal markup di partenza.
Un passo avanti
A partire dai CSS 2.1, l’introduzione del display:table ha permesso un balzo in avanti, consentendo di utilizzare una visualizzazione in stile tabella per realizzare layout complessi ma senza il problema del clearing, tipico del float.
Anche il display:table presenta tuttavia alcuni limiti (di cui però non parlerò perché non rientra negli obiettivi di questo articolo).
Flexible Layout, la soluzione definitiva?
La genesi dei flex layout è piuttosto complicata: la prima versione risale addirittura al 2009 e da allora i flexible layout hanno cambiato pelle più volte.
Se le precedenti versioni erano promettenti ma acerbe (anche per problemi di prestazioni), quella attuale sembra decisamente migliorata, potente e discretamente veloce (anche se i table layout sembrano più veloci).
Siamo dunque di fronte alla soluzione definitiva al problema della gestione dei layout? Vediamo…
Iniziamo…
Il primo passo da compiere è quello di applicare al contenitore una regola con display: flex (erano rispettivamente display: box e display: flexbox nelle due precedenti versioni).
Tutti gli esempi che farò d’ora in poi in questo articolo verranno applicati a questo markup:
<div id="container"> <aside id="news">NEWS</aside> <aside id="sponsor">SPONSOR</aside> <main id="content">CONTENT</main> </div>
Al quale aggiungiamo un paio di righe di CSS (ometto per brevità le regole di formattazione pura e semplice, come caratteri, colori, ecc…)
#container > aside, #container > main { box-sizing: border-box; text-align: center }
Questo è l’aspetto iniziale:
Il primo passo per iniziare ad usare i flexible layout sarà dunque:
#container { display: flex; }
Risultato:
Per default i box non sfruttano lo spazio a disposizione, ma si limitano ad occupare lo spazio minimo indispensabile per rendere visibile il contenuto. Rimediamo subito utilizzando la proprietà flex-grow, che si aspetta un valore numerico che indica la porzione di spazio a disposizione.
Nell’esempio che segue, #sponsor avrà una dimensione doppia di #news, mentre #content una dimensione tripla sempre rispetto a #news. Trattandosi di un layout fluido, le dimensioni verranno ricalcolate in base alla dimensione del viewport.
#news {flex-grow: 1;} #sponsor {flex-grow: 2;} #content {flex-grow: 3;}
Risultato:
Uno degli aspetti interessanti (ma non l’unico) dei flex sta nella possibilità di modificare molto facilmente l’ordine degli elementi:
#news {flex-grow: 1; order: 3;} #sponsor {flex-grow: 2; order: 2;} #content {flex-grow: 3; order: 1;}
Risultato:
Facile, vero? 😉
Un’altra interessante proprietà consente invece di cambiare l’orientamento del flusso: si tratta di flex-direction, che può assumere i valori row, row-reverse, column, column-reverse.
Il valore row è il predefinito, mentre con il valore column i box verranno disposti in colonna anziché in riga, rispettando order e flex-grow espressi in precedenza (quest’ultimo a patto di aver specificato una height per il contenitore):
#container { display: flex; height: 400px; flex-direction: column; }
Risultato:
Gli altri due valori disponibili per la proprietà flex-direction consentono di invertire la direzione del flusso.
Layout a riga singola / multipla: flex-wrap
Un flex container, per default, cerca di mantenere tutti i suoi elementi figli in una singola riga. E’ tuttavia possibile decidere di modificare questo comportamento sfruttando la proprietà flex-wrap: vediamo come funziona…
Per cominciare, inseriamo la proprietà flex-wrap nella regola del selettore #container (flex-wrap si applica al contenitore flex). I valori possibili sono:
- nowrap: è il valore di default ed impone che gli elementi figli rimangano su un’unica riga
- wrap: gli elementi possono essere separati in più righe se necessario
- wrap-reverse: gli elementi possono essere separati in più righe se necessario ed il loro ordine è invertito rispetto all’ordine originale
#container { display: flex; flex-wrap: wrap; }
Aggiungiamo quindi due proprietà nella regola con il selettore che include tutti gli elementi figli del contenitore flex:
- flex-grow: 1;
- min-width: 300px;
#container > aside, #container > main { box-sizing: border-box; text-align: center; flex-grow: 1; min-width: 300px; } #news {order: 3;} #sponsor {order: 2;} #content {order: 1;}
Risultato:
- Se la “larghezza utile” è pari o superiore ai 900px (3*300px), il layout si presenta in questo modo:
- Se la “larghezza utile” scende sotto i 900px (3*300px), il layout si presenta in questo modo:
Suggerimento: Questo è solo uno dei modi per sfruttare flex-wrap per ottenere la “suddivisione” degli elementi in più righe… prova, ad esempio, a sostituire flex-grow: 1 con width: 33%.
Distribuzione degli elementi in una riga: justify-content
Supponiamo adesso di dover posizionare elementi a dimensione fissa all’interno di un contenitore con dimensione superiore o addirittura variabile: la proprietà justify-content ci consente di scegliere come distribuire gli elementi figli. I valori ammessi sono:
- flex-start: è il valore di default e posiziona gli elementi a partire da sinistra, mantenendoli ravvicinati
- flex-end: posiziona gli elementi a partire da destra, mantenendoli ravvicinati
- center: posiziona gli elementi al centro, mantenendoli ravvicinati
- space-between: il primo elemento viene posizionato a sinistra, l’ultimo a destra e lo spazio residuo (differenza tra la larghezza del contenitore e la somma delle larghezze degli elementi figli) viene distribuito tra gli altri elementi
- space-around: lo spazio residuo viene diviso per il numero di margini (n. di elementi * 2), quindi applicato ad ogni margine
Esempi:
#container { display: flex; justify-content: space-between; } #container > * { box-sizing: border-box; text-align: center } #news {width: 25%; order: 3;} #sponsor {width: 25%; order: 2;} #content {width: 25%; order: 1;}
Risultato:
Sostituiamo adesso justify-content: space-between con justify-content: space-around…
Risultato:
Posizionamento verticale degli elementi: align-items
Se gli elementi figli di un contenitore flex hanno altezze diverse tra loro e comunque inferiori a quelle del contenitore, la proprietà align-items (da applicare al contenitore) ci permette di stabilire il posizionamento degli elementi.
I valori ammessi sono:
- stretch: è il valore di default ed impone lo stretch verticale degli elementi per fare in modo che l’altezza sia uguale a quella del contenitore
- flex-start: gli elementi vengono allineati al bordo superiore del contenitore. L’eventuale spazio residuo rimarrà sotto agli elementi
- flex-end: gli elementi vengono allineati al bordo inferiore del contenitore. L’eventuale spazio residuo rimarrà sopra agli elementi
- center: gli elementi verranno allineati verticalmente al centro del contenitore
- baseline: gli elementi verranno allineati sulla linea di base del testo contenuto in essi
#container { width: 100%; height: 100px; border: 1px solid #000; display: flex; align-items: center; /*allineamento verticale */ } #container > * { box-sizing: border-box; text-align: center } #news {flex-grow: 1; order: 3; line-height: 40px;} #sponsor {flex-grow: 2; order: 2; line-height: 80px;} #content {flex-grow: 4; order: 1; line-height: 60px;}
Risultato:
Sostituiamo align-items: center con align-items: flex-start
Adesso puoi procedere in autonomia, testando i risultati con gli altri valori.
Conclusioni
Abbiamo esplorato quasi tutte le proprietà che ruotano intorno ai flex layout e ritengo che quanto visto sia più che sufficiente per intuire le potenzialità dello strumento e con un po’ di creatività e di fantasia le possibilità sono davvero notevoli.
A mio modo di vedere può rappresentare la “luce in fondo al tunnel”, dopo anni di layout creati esclusivamente con il float (o quasi…).
Ma è tutto oro ciò che luccica? Purtroppo, come al solito, no… 🙁
Il problema principale dei flex layout è lo scarso supporto da parte dei browser meno recenti (come sempre il problema è rappresentato principalmente da IE e dalla frammentazione delle sue installazioni).
Dato che il supporto da parte dei browser cambia costantemente, ti consiglio di dare un’occhiata qui: http://caniuse.com/#search=flex
Un altro problema è secondo me dato dalla scarsa uniformità dei nomi delle proprietà e dalla complessità generale del sistema, la cui curva di apprendimento è piuttosto ripida.
E tu cosa ne pensi?
Se vuoi saperne di più: http://www.w3.org/TR/css3-flexbox/