Flexbox

Traduzione in corso.

{{LearnSidebar}}
{{PreviousMenuNext("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}
Flexbox è un metodo di layout monodimensionale per disporre i componenti in righe oppure in colonne. Quando l'area che li contiene aumenta, i componenti si espandono per colmarne lo spazio, quando invece si restringe anche i componenti si restringono.
Questo articolo comprende i concetti fondamentali.
Prerequisiti: Le basi di HTML (leggi Introduzione a HTML) e nozioni sul funzionamento del CSS (leggi Introduzione a CSS.)
Obiettivo: Apprendere l'utilizzo di Flexbox per impostare il layout delle pagine web.

Perchè Flexbox?

Per molto tempo, le uniche tecniche affidabili per creare layout CSS compatibili con tutti i browser utilizzavano elementi float e posizionamento. Funzionavano a sufficienza, ma erano per alcuni aspetti limitati e frustranti.

Per esempio con quelle tecniche era difficile o del tutto impossibile definire in maniera flessibile e vantaggiosa le seguenti impostazioni:

  • Centrare verticalmente un blocco di contenuti all'interno del proprio contenitore.
  • Fare in modo che i figli di un contenitore occupino lo stesso spazio in larghezza o altezza indipendentemente dalle dimensioni del contenitore stesso.
  • Fare in modo che in un layout multicolonna, le colonne siano ugualmente alte anche se i loro contenuti differiscono per lunghezza.

Nelle sezioni seguenti apprenderemo come flexbox faciliti notevolmente questi compiti. Iniziamo!

Introduzione a un semplice esempio

Questo articolo presenta una serie di esercizi per aiutare a comprendere il funzionamento di flexbox. Per cominciare copiamo in locale il file di partenza flexbox0.html presente in github. Carichiamolo con un browser moderno, ad esempio Firefox o Chrome e facciamo attenzione al codice nell'editor. É possibile in alternativa visionarlo attraverso la versione live.

Image showing the starting point of Flexbox tutorial

Come vediamo la pagina è formata da un {{htmlelement("header")}} contenente il titolo principale, poi un elemento {{htmlelement("section")}} che contiene tre {{htmlelement("article")}}. Partiamo da questa situazione per creare un layout a tre colonne abbastanza comune.

Individuare gli elementi da impostare come box flessibili

Per cominciare occorre scegliere il gruppo di elementi che devono apparire come box flessibili; per farlo occorre impostare un valore particolare della proprietà {{cssxref("display")}} del loro elemento padre. In questo caso specifico desideriamo sistemare gli elementi {{htmlelement("article")}}, perciò agiamo sul loro contenitore {{htmlelement("section")}}:

section {
  display: flex;
}

Questa impostazione trasforma <section> in un contenitore flex e gli elementi figli in componenti flex. Questo è l'aspetto che otteniamo:

Proprio così: con questa semplice regola abbiamo già ottenuto tutto ciò che volevamo! Il layout diventa multicolonna e le colonne che lo formano sono della medesima larghezza e lunghezza. Tutto ciò avviene grazie ai componenti flex, cioè i figli del contenitore impostato come flex, che, grazie a valori predefiniti, risolvono automaticamente problemi tipici come questo.

Ripassiamo cosa è avvenuto: l'elemento il cui valore di  {{cssxref("display")}} è flex si comporta come un elemento blocco all'interno della pagina, ma i suoi figli vengono disposti come componenti flex. Nella prossima sezione capiremo meglio che cosa significa. Notiamo che in alternativa possiamo usare il valore inline-flex per display cosicché gli elementi figlio diventano comunque componenti flex, ma il contenitore si comporta come un elemento in linea.

Il modello flex

In qualità di componenti flex, gli elementi si dispongono lungo due assi:

flex_terms.png

  • L’asse principale (main axis) è l'asse che traccia la direzione lungo la quale i componenti si dispongono, corrispondente in senso orizzontale alle righe oppure in senso verticale alle colonne. Definiamo l'inizio e la fine di questo asse inizio dell'asse principale (main start) e termine dell'asse principale (main end).
  • L’asse traverso (cross axis) è l'asse perpendicolare alla direzione dei componenti flex. Definiamo l'inizio e la fine di questo asse inizio dell'asse traverso (cross start) e termine dell'asse traverso (cross end).
  • L'elemento su cui viene impostata la regola display: flex, che nel nostro esempio è {{htmlelement("section")}} è chiamato contenitore flex (flex container).
  • Gli elementi disposti come box flessibili all'interno del contenitore flex vengono chiamati componenti flex (flex items), che nel nostro caso sono gli elementi {{htmlelement("article")}}.

Si tengano a mente queste definizioni durante le sezioni successive. In caso di confusione con i termini potete comunque tornare a rileggere questa sezione.

Colonne o righe?

Flexbox offre una proprietà chiamata flex-direction {{cssxref("flex-direction")}} che indica quale direzione deve seguire l'asse principale, ovvero come vengono disposti i contenuti flexbox;il valore predefinito è row, in modo che i contenuti si schierino in riga secondo il verso della lingua preimpostata dal browser, che per le quelle occidentali è da sinistra a destra.

Proviamo ad aggiungere la seguente dichiarazione alle regole di {{htmlelement("section")}}:

flex-direction: column;

Come vediamo i componenti tornano a schierarsi in colonna, come in un il flusso normale senza aggiungere CSS. Cancelliamo pure questa dichiarazione dall'esercizio, prima di continuare.

Nota: Potremmo anche invertire la disposizione dei componenti flex utilizzando i valori row-reverse o column-reverse. Sono da sperimentare!

Effettuare il Wrapping

Il problema che sorge nel layout quando la larghezza o l'altezza vengono esplicitate è che il gruppo dei contenuti flexbox potrebbe eccedere il limite del contenitore, guastando il layout. Diamo un'occhiata all'esempio flexbox-wrap0.html,di cui viene fornita la visione live. Per eseguire le procedure mostrate da questo punto in poi, salvate una copia del file in locale.

Come vediamo i contenuti figli eccedono effettivamente il limite del loro contenitore. Una possibile soluzione consiste nell'aggiungere la seguente dichiarazione alle regole di {{htmlelement("section")}}:

flex-wrap: wrap;

Proviamo anche ad aggiungere la seguente dichiarazione alle regole di {{htmlelement("article")}}:

flex: 200px;

Ricaricando possiamo notare il miglioramento che abbiamo ottenuto grazie queste modifiche.

Adesso possiamo notare che si sono formate un certo numero di righe, ovviamente tante quante ne servono per tutti i contenuti flexbox: quando un contenuto eccede i limiti, scala alla riga successiva. L'impostazione flex: 200px dichiarata per gli articoli significa che ognuno di essi occuperà almeno 200px; questa proprietà verrà discussa con maggior dettaglio più avanti nell'articolo. Notiamo anche che ciascuno degli ultimi contenuti che occupano l'ultima riga è molto più largo in modo da riempirla completamente.

Possiamo sperimentare ancora: innanzitutto assegnare alla proprietà {{cssxref("flex-direction")}} il valore row-reverse, così da ottenere un layout con numerose righe come il precedente in cui però i contenuti si schierano a partire dall'angolo opposto della finestra del browser e fluiscono in maniera inversa.

La forma contratta flex-flow

Occorre notare a questo punto che esiste una forma contratta, {{cssxref("flex-flow")}, per le proprietà {{cssxref("flex-direction")}} e {{cssxref("flex-wrap")}} — }. É possibile per esempio sostituire

flex-direction: row;
flex-wrap: wrap;

con

flex-flow: row wrap;

Dimensionamento flessibile dei componenti flex

Ora torniamo al primo esempio per capire come determinare la proporzione che occupa ogni componente flex nello spazio rispetto ai componenti suoi pari. Riapriamo il file locale flexbox0.html, oppure, come punto di partenza, prendiamo il nuovo file flexbox1.html di cui viene fornita anche la versione live.

Cominciamo aggiungendo la seguente regola al termine del nostro CSS:

article {
  flex: 1;
}

Si indica in questo modo un valore proporzionale, privo di unità di misura, che determina lo spazio che occupa ogni componente flex rispetto agli altri. In questo caso tutti gli elementi {{htmlelement("article")}} hanno valore 1, il che significa, al netto di spaziature interne (padding) ed esterne (margin), che lo spazio verrà equamente ripartito tra tutti i componenti. Questo è un valore relativo a tutti i componenti flex del medesimo gruppo, perciò, se invece di 1 viene scritto un altro valore, 400000 ad esempio, otteniamo lo stesso risultato.

Di seguito scriviamo questa regola:

article:nth-of-type(3) {
  flex: 2;
}

Si noti, dopo aver ricaricando la pagina, che il terzo componente {{htmlelement("article")}} riempie il doppio dello spazio occupato da ciascuno degli altri due. Lo spazio totale è ora diviso in quattro, cioè una spaziatura per il primo elemento, una per il secondo e due per il terzo (1+1+2=4), quindi il primo e il secondo occupano un quarto (1/4) di spazio ciascuno mentre il terzo ne occupa due quarti (2/4) ovvero la metà.

Si può anche specificare una misura reale minima al di sotto del quale non è possibile andare. Correggiamo le regole degli articoli in questo modo:

article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 2 200px;
}

Con queste regole affermiamo fondamentalmente quanto segue: "Ogni componente flex occupa almeno 200px nello spazio a disposizione, mentre lo spazio che rimane viene occupato rispettando le unità proporzionali." Ricaricando la pagina possiamo notare la differenza nella ripartizione delle spaziature.

La potenza di flexbox risiede nella sua flessibilità ovvero nella responsività con cui gestisce il layout: se ridimensioniamo la finestra del browser oppure inseriamo un nuovo elemento {{htmlelement("article")}} il layout continuerà a funzionare bene.

flex: forma contratta al posto della forma estesa

La proprietà  {{cssxref("flex")}} rappresenta la forma contratta delle seguenti tre proprietà::

  • la proporzione, priva di unità di misura reale, di cui abbiamo già discusso, che può essere individualmente espressa utilizzando la forma estesa {{cssxref("flex-grow")}}.
  • Una seconda unità proporzionale, {{cssxref("flex-shrink")}} che gioca un ruolo importante nel momento in cui i componenti flex stanno per oltrepassare i limiti del contenitore, specificando la misura in cui questi componenti possono restringersi in modo da non sbordare. Questa però è una proprietà piuttosto avanzata di flexbox che eviteremo di approfondire in questo articolo.
  • Una spaziatura reale minima di cui abbiamo già parlato, che può essere individualmente espressa utilizzando la forma estesa flex-basis {{cssxref("flex-basis")}}.

È consigliabile non utilizzare le forme estese della proprietà flex, a meno che non si possa fare altrimenti, come per esempio sostituire un valore stabilito in precedenza, perché costringono a scrivere una maggior quantità di codice che può risultare in qualche modo confusionario.

Allineamento orizzontale e verticale

Con flexbox è possibile allineare i componenti flex lungo l'asse principale (main axis) o lungo l'asse traverso (cross axis). Facciamo alcune prove con la nuova pagina di esempio, flex-align0.html di cui è presente anche la versione live , per mostrare come creare una bottoniera, o barra degli strumenti, semplice e flessibile.

Apriamo il codice in locale.

Aggiungiamo al termine del file CSS la regola seguente:

div {
  display: flex;
  align-items: center;
  justify-content: space-around;
}

Dopo aver ricaricato la pagina, i bottoni vengono ben centrati, sia orizzontalmente che verticalmente. Abbiamo ottenuto questo risultato operando con due nuove proprietà:

Attraverso {{cssxref("align-items")}} controlliamo l'allineamento rispetto all'asse traverso (cross axis).

  • Il valore predefinito è stretch, che allunga o comprime tutti i componenti flex affinché riempiano lo spazio del loro contenitore lungo l’asse traverso (cross axis). In un contenitore che non ha una misura fissa lungo l’asse traverso, tutti quanti suoi componenti assumono la lunghezza del maggiore fra di loro, perciò nel primo esempio dell'articolo tutti i componenti risultano della stessa altezza senza doverlo specificare.
  • In questo esempio viene invece specificato il valore center, per cui ogni componente si dimensiona in funzione del contenuto che possiede, in base a questa dimensione viene quindi centrato lungo l’asse traverso. Questa è la ragione per cui, in questo esempio, i bottoni che sono centrati in verticale.
  • Altri valori disponibili sono flex-start e flex-end, che allineano i componenti rispettivamente all’inizio o al temine dell’asse traverso. Per i dettagli vai {{cssxref("align-items")}}.

É possibile sostituire l'impostazione data da align-items {{cssxref("align-items")}} , utilizzando la proprietà {{cssxref("align-self")}} di ogni singolo componente figlio. Ad esempio se proviamo ad aggiungere la seguente regola:

button:first-child {
  align-self: flex-end;
}

Dopo aver verificato l’effetto, possiamo cancellare questa regola per ritornare alla situazione precedente.

Attraverso {{cssxref("justify-content")}} controlliamo il tipo di schieramento dei componenti flex lungo l'asse principale (main axis).

  • Il valore predefinito è flex-start, per cui il gruppo dei componenti si posiziona all'inizio dell'asse principale.
  • Con flex-end, il gruppo si posiziona al termine.
  • Con center o altrimenti justify-content, l'allineamento parte dal centro dell'asse principale.
  • Con space-around, che è il valore utilizzato nell'esempio, i componenti si distribuiscono equamente lungo l'asse principale; inoltre viene creato un margine all'inizio e al termine dell'asse.
  • Con space-between impostiamo una situazione molto simile a space-around, eccettuati i margini alle estremità che non vengono creati.

É consigliabile sperimentare le proprietà con valori suddetti prima di continuare a leggere l'articolo.

Ordinare i componenti flex

Con flexbox è possibile cambiare l'ordine dei componenti senza intervenire manualmente nel sorgente HTML. Questa opportunità non esisteva con le metodologie di layout precedenti.

Proviamo ad aggiungere al CSS una nuova semplice regola:

button:first-child {
  order: 1;
}

Una volta ricaricato notiamo che il bottone con label "Sorriso" si è spostato al termine dell'asse principale. Vediamo in dettaglio cosa è successo:

  • Il valore predefinito della proprietà {{cssxref("order")}} di tutti i componenti flex è 0.
  • I componenti flex che hanno un valore di ordine maggiore compaiono dopo a quelli con un ordine minore.
  • I componenti flex che hanno lo stesso valore compaiono nello stesso ordine del sorgente HTML. Poniamo ad esempio di avere quattro componenti il cui corrispettivo valore è 2, 1, 1 e 0; il loro ordine di apparizione risulterà questo: all'inizio il quarto, poi il secondo, poi il terzo e al termine il primo.
  • Il terzo appare dopo il secondo perché hanno lo stesso valore order, dunque viene rispettata la successione con cui vengono definiti nel sorgente.

Se impostiamo un valore negativo di order, il componente compare prima di quelli con valore 0. Proviamo ora ad applicare la regola impostando per esempio l'ordine del bottone "Imbarazzo":

button:last-child {
  order: -1;
}

Flex box annidati

Con flexbox possiamo creare layout piuttosto complessi; è del tutto lecito impostare un componente flex in modo che contenga a sua volta componenti annidati flex che vengono visualizzati come flex box. Diamo un'occhiata a complex-flexbox.html (see it live also).

La struttura HTML è abbastanza semplice, l'elemento {{htmlelement("section")}} contiene gli elementi figli {{htmlelement("article")}}. , il terzo di questi contiene tre {{htmlelement("div")}} :

section - article
          article
          article - div - button   
                    div   button
                    div   button
                          button
                          button

Ora guardiamo il codice che ha creato il layout.

Innanzitutto, impostiamo i figli di {{htmlelement("section")}} affinché diventino flex box.

section {
  display: flex;
}

Quindi valorizziamo alcune proprietà flex all'interno degli stessi {{htmlelement("article")}}. Si noti in particolare la seconda regola, in cui si impone che il terzo elemento {{htmlelement("article")}} abbia a sua volta componenti innestati flex, i quali però devono essere incolonnati.

article {
  flex: 1 200px;
}

article:nth-of-type(3) {
  flex: 3 200px;
  display: flex;
  flex-flow: column;
}

Quindi, impostiamo per il primo <div> la proprietà flex a 1 100px; in modo che abbia un'altezza reale di almeno 100px; la proprietà successiva stabilisce che anche gli elementi figli, cioè i (the {{htmlelement("button")}}, divengano componenti flex; tali elementi si dispongono in riga e allineati a partire dal centro dello spazio disponibile mantenendo i margini alle estremità, proprio come l'esempio del bottone visto in precedenza.

article:nth-of-type(3) div:first-child {
  flex:1 100px;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  justify-content: space-around;
}

Infine viene definita una regola per la dimensione dei bottoni., ma la parte più interessante è la proprietà flex che ha valore 1 auto; questa impostazione genera un comportamento peculiare che notiamo quando restringiamo la finestra del browser: i bottoni cercano di occupare il massimo dello spazio disponibile, si schierano uno accanto all'altro finché c'è spazio disponibile, e poi scalano alla riga seguente.

button {
  flex: 1 auto;
  margin: 5px;
  font-size: 18px;
  line-height: 1.5;
}

Compatibilità tra browser

Gran parte delle ultime versioni dei browser supportano flexbox, cioè Firefox, Chrome, Opera, Microsoft Edge, IE 11, le versioni recenti di Android/iOS ecc. Occorre tuttavia considerare anche la presenza delle versioni antiquate dei browser che non supportano flexbox oppure lo fanno solo parzialmente.

Il problema non incide granché quando ne studiamo e ne proviamo le funzionalità, tuttavia quando si cerca di utilizzare flexbox per creare un sito web reale dobbiamo controllare e assicurarci che l'esperienza utente sia comunque accettabile in quanti più browser possibile.

Applicare flexbox è un po' più complicato di altre funzionalità CSS. Se per esempio il browser non supporta l'ombreggiatura (drop shadow) è facile che l'usabilità del sito rimanga comunque valida, se invece manca il supporto a flexbox è probabile che il layout della pagina si disintegri rendendola inutilizzabile.

Le strategie per ovviare ai problemi di compatibilità tra browser vengono affrontate nel modulo Cross browser testing.

Metti alla prova le tue capacità!

Questo articolo è denso di informazioni, ma riesci a ricordare quelle più importanti?

Prima di continuare possiamo verificare la nostra comprensione alla pagina Test your skills: Flexbox.

Sommario

In conclusione dell'articolo sulle basi di flexbox speriamo di aver suscitato interesse e un buon punto di partenza nel nostro percorso di apprendimento. Nel prossimo articolo ci occupiamo di un altro importante aspetto del layout CSS: le Griglie CSS.

{{PreviousMenuNext("Learn/CSS/CSS_layout/Normal_Flow", "Learn/CSS/CSS_layout/Grids", "Learn/CSS/CSS_layout")}}