La proprietà float è senza dubbio una delle più utili e usate dei CSS, soprattutto per organizzare layout e sezioni di pagina. Ne abbiamo parlato in moltissime occasioni, per esempio nella Guida ai layout con i CSS, e negli articoli:
- Capire il box model,
- Layout liquido a 2 colonne con i CSS,
- Layout a due e tre colonne,
- Risoluzione dei problemi dei CSS.
Questo articolo, oltre ad essere un breve riepilogo delle cose essenziali da sapere sui float, nasce con lo scopo di presentare alcune soluzioni pratiche alla luce delle tecniche più solide.
Float: la teoria in breve
Come abbiamo visto nell'articolo sul Capire il box model, elementi float vengono resi automaticamente block-level: questo significa che si può attribuire loro una larghezza e/o un altezza via CSS.
A differenza degli elementi block-level normali, gli elementi float oltre ad essere auto-adattanti in altezza (ossia assumere l'altezza necessaria al contenuto) lo sono anche in larghezza. Questo significa che un elemento float assumerà la larghezza massima per il suo contenuto, fino ad espandersi per tutta la larghezza del suo contenitore.
È essenziale considerare che gli elementi float vengono traslati dal flusso degli elementi di pagina verso uno dei due estremi del loro contenitore, e che elementi adiacenti nel codice "sentono" la loro presenza, regolandosi di conseguenza. Ciò nonostante, gli antenati degli elementi float, ossia i loro contenitori, li ignorano.
Una compagna quasi inseparabile della proprietà float è la proprietà clear che, se applicata ad un elemento successivo ad uno reso float, impedisce che questo subisca il float.
Controllare la larghezza di un elemento float
Come abbiamo accennato i float sono, a differenza di elementi block-level normali, auto-adattanti in larghezza, ovvero se non hanno una larghezza o dei margini impostati, si espanderanno in orizzontale fino alla larghezza del loro contenitore. (o almeno in via teorica: questo non succedeva infatti in Internet Explorer 6).
Ho preparato un semplice esempio per mostrare come elementi float si espandano in orizzontale a seconda del loro contenuto. È un esempio molto semplice, il comportamento che ci si aspetta è questo (con le vecchie versioni di IE notavamo differenze di resa tra IE e gli altri browser):
In ogni caso, gli effetti di float non controllati in larghezza sono imprevedibili, soprattutto in casi reali in cui non ci sono solo elementi float.
Una buona pratica è quindi costringere il float in larghezza. I modi possibili sono due:
- Attribuire una larghezza al suo contenuto, o usare esclusivamente contenuto di larghezza nota.
- Dichiarare la larghezza dell'elemento float.
La prima soluzione è indicata in casi elementari: ecco un semplice esempio in cui un div
viene reso float per contenere un'immagine. Ecco il codice HTML con stili in linea:
<div style="float:right; margin:0 0 5px 5px">
<img src="ink.jpg">
</div>
La seconda soluzione è decisamente la più pratica e usata, e si rivela essenziale nella maggior parte dei casi. Ecco un piccolo esempio in cui un div
che rappresenta un box generico viene reso float. La regola CSS necessaria è questa:
div#newsbox
{
float:right;
display:inline; /* per i vecchi IE , si può omettere */
width:150px;
margin:5px;
background: #09C865
}
(La dichiarazione display:inline serve per sistemaare un vecchio bug di Internet Explorer: raddoppia il margine concorde all'elemento float.)
Distanziare i float
Nella maggior parte dei casi, soprattutto per i layout a due o tre colonne, è importante evitare che un elemento si mantenga distanziato da un lato del suo contenitore anche quando termina l'effetto di uno dei float adiacenti. Ci sono tre modi ottenere un effetto simile:
- Usare i margini.
- Specificare la larghezza dell'elemento adiacente al float.
- Usare i float opposti.
Applicheremo le tre possibili soluzioni ad un semplice layout a due colonne che usa la tecnica delle false colonne, di cui abbiamo parlato in questo articolo.
Usare i margini
L'uso dei margini è senza dubbio il più diffuso per distianziare un elemento. Vediamo subito l'esempio. Ecco il codice HTML minimale:
<div id="container">
<div id="header"><h1>Layout a due colonne</h1></div>
<div id="sidebar">
<p>Qui la navigazione.</p>
</div>
<div id="content">
<p>Qui il contenuto.</p>
</div>
<div id="footer"><p>Qui il footer</p></div>
</div>
Ed ecco la parte del CSS per il layout:
div#container
{
width:600px;
margin:0 auto;
text-align:left;
background: url(bk.jpg)
}
div#header
{
background: #7EA9C7;
border-bottom:1px solid #000
}
div#content { margin-right:160px }
div#sidebar { float:right;width:160px }
div#footer
{
clear: both;
width:600px;
border-top:1px solid #000;
background: #F1EFE2
}
Importante notare l'uso della proprietà clear sul footer, che rende il layout stabile nel caso in cui la navigazione sià più lunga dei contenuti.
Questa soluzione è soggetta ad un ben noto bug delle vecchie versioni di IE che è il 3 pixel jog. In sostanza il float aggiunge tre pixel di margine a cui è soggetto l'elemento adiacente al float, incidendo sul testo in particolare. Se nella versione con la colonna laterale a destra questo difetto di IE è praticamente impercettibile, lo è molto di più nella versione con colonna di navigazione a sinistra, di cui ho realizzato uno screenshot:
Per sistemare le cose ci sono diversi modi, e in particolare hack, di cui abbiamo parlato nell'articolo sulla risoluzione dei problemi. Il modo più semplice, standard e senza hack è a parer mio l'uso delle seguenti regole aggiuntive:
div#content{height:1%}
*>div#content{height:auto}
Ecco quindi l'esempio che, oltre all'uso dei margini include queste due regole. In sostanza la prima regola viene interpretata solo da IE, mentre la seconda da tutti i browser con un supporto migliore dei CSS; da notare che l'altezza all'1% in IE non ha effetti, se non quello di eliminare il bug.
Specificare la larghezza
Un' altro modo per distanziare un elemento adiancente ad un float è specificarne la larghezza. C'è una questione: in questo caso il 3pixel jog può rivelarsi rovinoso per il layout su Internet Explorer, causando una traslazione verso il basso della colonna dei contenuti pari all'intera altezza della colonna di navigazione.
Ecco il caso. Rivediamo l'esempio precedente. Si tratta di un semplice layout a due colonne largo in totale 600 pixel: ai contenuti sono dedicati 440px di larghezza, i rimanenti 160 sono per la colonna di navigazione. Se proviamo a togliere i margini e a specificare le due larghezze nel CSS ecco cosa succede in Internet Explorer:
Una possibile soluzione, senza dover ricorrere ad hack, è specificare una larghezza per il div dei contenuti inferiore di almeno tre pixel alla larghezza massima che potremo attribuirgli. Ecco quindi il risultato, che funziona anche su IE, in cui abbiamo definito le due regole CSS:
div#content{width:437px}
*>div#content{width:440px}
IE quindi assegnerà 437px di larghezza, mentre in tutti i browser moderni con supporto del child selector, i contenuti saranno larghi 440px.
Se per il layout con navigazione a destra abbiamo ottenuto un layout stabile, robusto e cross-browser solo dichiarando la larghezza del container, per il layout con la navigazione a sinistra oltre che a specificare la larghezza dovremo anche specificare i margini. Se non lo facciamo, ecco cosa otteniamo sia in Opera che Firefox:
Ovvero la colonna di navigazione viene inglobata nella colonna dei contenuti, con effetti disastrosi. In questo caso la regola per il div dei contenuti per un layout stabile è:
div#content{width:437px;margin-left:160px}
*>div#content{width:440px}
Ecco quindi l'esempio che ora funziona anche su Opera e Firefox.
Abbiamo visto brevemente le cose essenziali da sapere sul float, e alcuni esempi pratici di questa proprietà per il layout, affrontando questioni pratiche e problemi di resa.
Le soluzioni che usano margini e/o larghezza per distanziare elementi float che abbiamo visto, seppur valide, presentano dei microscopici difetti e differenze di resa delle spaziature tra Internet Explorer e gli altri browser. Inoltre, non sono purtroppo precise al pixel (almeno su IE) come vorremo che fossero, dato che in alcuni casi abbiamo dovuto sacrificare tre pixel per evitare un annoso bug di IE.
Le cose si sarebbero potute sistemare in molti modi, ho cercato però di presentare le soluzioni che ritengo più semplici e pulite: a parer mio gli hack sono da evitare il più possibile, dato che ad oggi non possiamo sapere quali effetti avranno sui browser futuri.
Vedremo come sia possibile ottenere un layout pixel-perfect usando la tecnica dei float opposti, senza ricorrere ad hack o workaround, insieme a moltre cose che riguardano i float.
Abbiamo visto brevemente alcune nozioni elementari sulla proprietà float e sul suo utilizzo per realizzare un semplice layout a due colonne. In questa seconda parte presenteremo due novità molto importanti che riguardano i float: ovvero i float opposti e come contenere i float i float senza markup aggiuntivo. In chiusura di articolo mostreremo una variante delle false colonne per impaginare contenuti di pagina. Iniziamo subito.
Usare i float opposti
Un'alternativa alle due strategie per realizzare layout a due colonne di cui abbiamo parlato nello scorso appuntamento è la tecnica dei float opposti, a cui sono arrivato di recente dopo un po' di sperimentazioni. In sostanza, si tratta di rendere le due colonne (contenuti e navigazione) float una a destra e una a sinistra, specificando la larghezza effettiva e precisa al pixel. Vediamo subito l'esempio. Ecco il codice HTML minimale:
<div id="container">
<div id="header"><h1>Layout a due colonne</h2></div>
<div id="sidebar">
<p>Qui la navigazione.</p>
</div>
<div id="content">
<p>Qui il contenuto.</p>
</div>
<div id="footer"><p>Qui il footer</p></div>
</div>
Ed ecco la parte del CSS per il layout:
div#container
{
width:600px;
margin:0 auto;
text-align:left;
background: url(bk.jpg)
}
div#header
{
background: #7EA9C7;
border-bottom:1px solid #000
}
div#content
{
float: left;
width: 440px
}
div#sidebar
{
float: right;
width: 160px
}
div#footer
{
clear: both;
width:600px;
border-top:1px solid #000;
background: #F1EFE2
}
In sostanza abbiamo la colonna dei contenuti larga 440 pixel e float a sinistra, mentre la colonna di navigazione è resa float a destra e dichiarata di 160 pixel (in questo caso nei vecchi IE non si presenta il "3 pixel jog" che si verifica, a quanto pare, quando ci sono elementi non-float affiancati da elementi float). Il layout è quindi robusto e perfetto al pixel.
La tecnica è molto semplice, non presenta bug e ha la stessa resa sui IE 5, IE 5.5, IE6, Opera 7.6 e Firefox, Safari. La compatibilità è decisamente buona quindi, e non abbiamo dovuto usare nè hack nè workaround: è bastato pensare le cose in maniera differente.
Ho preparato altri due esempi che usano la tecnica: un layout con navigazione più lunga dei contenuti (in cui il CSS è lo stesso dell'esempio appena visto) e un layout con navigazione a sinistra. Anche in quest'ultimo esempio non ci sono vincoli sulla lunghezza relativa delle due colonne.
Float opposti e colonne ordinate nell'HTML
La tecnica dei float opposti è utilissima per superare un limite finora intrinseco dei layout con i float, ovvero che la colonna di navigazione debba precedere nell'HTML la colonna dei contenuti. Vediamo l'esempio che ho preparato. Se guardate il codice HTML, noterete che la colonna dei contenuti precede la colonna di navigazione. Ecco l'HTML minimale:
<div id="container">
<div id="header"><h1>Layout a due colonne ordinate</h1></div>
<div id="content">
<p>Qui il contenuto.</p>
</div>
<div id="sidebar">
<p>Qui la navigazione.</p>
</div>
<div id="footer"><p>Qui il footer</p></div>
</div>
Ed ecco le regole CSS chiave:
div#content { float: left; width: 440px }
div#sidebar { float: right; width: 160px }
div#footer { clear: both}
Per completezza, ho preparato anche l'esempio con la colonna di navigazione a sinistra, in cui il markup è quello appena visto: è bastato invertire nel CSS i due float.
Il layout con colonne ordinate e float opposti presenta molti vantaggi. Tra questi, una buona compatibilità cross-browser, nessun vincolo di lunghezza relativa delle due colonne, migliore accessibilità verso screen-reader e browser testuali, e probabilmente migliori chance di posizionamento nei motori di ricerca rispetto ai layout a due colonne con float in cui la navigazione precede i contenuti.
Prima di passare al prossimo argomento, una piccola nota: nei layout liquidi se vorrete usare i float opposti dovrete avere cura di impostare le due percentuali di modo che la loro somma sia 99% e non 100% come dovrebbe essere. Infatti, solo per certe larghezze del browser (qualunque browser) problemi di arrotondamento delle percentuali calcolate fanno sì che la somma delle due larghezze sia poco più di 100%, ottenendo così layout in cui una delle due colonne inizia verticalmente dove l'altra finisce.
Contenere i float senza markup aggiuntivo
Abbiamo già accennato a come contenere i float nell'Risoluzione dei problemi dei CSS - I. In sostanza, un elemento reso float tende a sbordare dal suo contenitore. Vediamo un tipico esempio del problema. La soluzione più nota e diffusa, come indicato anche in un articolo di Eric Meyer è inserire, prima di chiudere il contenitore dell'elemento float, un elemento che da il clear, in questo modo:
<div style="clear:right"> </div>
Questa soluzione implica purtroppo l'uso di HTML puramente presentazionale anche se privo di contenuto.
Già un po' di tempo fa è comparsa una prima alternativa, che si rivela a parer mio troppo complessa e poco pratica.
A fine 2004 Steve Smith pubblica la FnE (float nearly everything), un metodo semplice, robusto e cross-browser per contenere i float senza markup aggiuntivo. In sostanza, si tratta di rendere float anche il contenitore dell'elemento float. Spesso sarà necessario attribuire anche una larghezza al contenitore principale. Vediamo subito l'esempio in cui abbiamo applicato la FnE. Ecco il codice HTML dell'esempio:
<div id="container">
<div id="newsbox">Elemento float</div>
<div id="content">Qui il contenuto</div>
</div>
Ed ecco il CSS:
div#container{float: left;width: 100%;background:#B1D4FF}
div#newsbox{float:right;display:inline;width:150px;
border: 1px solid #CCC;margin:5px;background: #FFC}
Ancora più recentemente è stata scoperta un' altra tecnica, simple clearing of floats in cui si spiega come contenere un float senza markup aggiuntivo ma grazie alla proprietà overflow. Vediamo l'esempio. Il markup è minimale ed è lo stesso dell'esempio precedente. Vediamo il CSS:
div#container{width:100%;overflow:auto;background:#B1D4FF}
div#newsbox{float:right;display:inline;width:150px;
border: 1px solid #CCC;margin:5px;background: #FFC}
Le due tecniche sono equivalenti come prestazioni, semplicità e resa cross-browser. In sostanza sia la proprietà float che la proprietà overflow hanno l'effetto di forzare il contenitore a contenere il float. Mi raccomando, cosa importantissima è che le due tecniche vanno usate dichiarando una larghezza specifica (anche in pixel va bene, oppure 100% se non possiamo fare altrimenti).
False colonne per i contenuti centrali
Una delle cose di cui non ho ancora parlato nei tanti articoli dedicati ai fogli di stile è come ottenere false colonne per i contenuti centrali. Vediamo subito il primo esempio in cui un div, che potrebbe essere usato per esempio per contenere delle news o sezioni in evidenza, è stato suddiviso in tre colonne che sembrano avere la stessa altezza, grazie ad una semplice immagine che contiene le linee verticali. Vediamo l'HTML:
<div id="news3">
<div>
<h3>Prima colonna..</h3>
</div>
<div>
<h3>Seconda Colonna..</h3>
</div>
<div>
<h3>Terza Colonna..</h3>
</div>
</div>
Ecco invece il CSS:
div#news3{width:480px;overflow: auto;background:url(3col.gif);
border:solid #8080FF;border-width: 1px 0}
div#news3 div{float: left;width: 160px}
Da notare che i bordi orizzontali sono stati aggiunti via css per chiudere la falsa tabella, e che i tre elementi float sono contenuti usando overflow: auto e senza markup aggiuntivo.
Vediamo anche un secondo esempio per le false tabelle. L'immagine di sfondo usata in questo caso ha anche la chiusura in fondo, ed è abbastanza alta per garantire un po' di contenuti. È una gif trasparente, così da mostrare il colore o lo sfondo sottostante.
Il markup è lo stesso dell'esempio precedente, vediamo il CSS:
div#news3{width:490px;overflow: auto;background:url(3col2.gif) no-repeat bottom}
div#news3 div{float: left;width: 150px;display:inline;
margin-left:10px;border-top: 1px solid #3366FF}
Entrambi i due esempi sono stati realizzati con la dichiarazione overflow:auto così da evitare di contenere i float con il markup. Tutti gli esempi sono disponibili anche per il download
Conclusioni e approfondimenti
Si conclude qui questo articolo sui float in cui, dopo aver visto nella prima parte un po' di teoria e alcune tecniche note, in questa seconda parte abbiamo visto alcune nuove applicazioni. Avrei voluto approfondire la teoria, ma ho ritenuto che è essenziale per capire a fondo le cose vederle in pratica.
Ci tengo però a citare due risorse molto valide (in inglese) sui float: Float Tutorial e Float Layouts. Mentre il primo è davvero tra uno dei migliori tutorial di webdesign per il livello di dettaglio, la suddivisione degli argomenti e la quantità di esempi, il secondo si presenta ricco di nozioni teoriche ma purtroppo è totalmente privo di esempi o immagini quindi potrebbe risultare un po' difficile da seguire. Segnalo inoltre l'ottima presentazione Float like a butterfly.