CSS: l'Easy Clearing per il clear dei float

CSS: l'Easy Clearing per il clear dei float

Quella che segue è la traduzione dell'articolo originale scritto da John Gallant e Holly Bergevin sulla tecnica di clearing dei float CSS che prese il nome di Easy Clearing proprio da questo articolo.

Il clear dei float alla vecchia maniera

Quando un float è contenuto all'interno di un box contenitore con un bordo visibile o uno sfondo, tale float non spinge automaticamente il limite inferiore del contenitore verso il basso all'aumentare della sua altezza. Al contrario, il float viene ignorato dal contenitore e sporgerà fuori da esso come una bandiera. Quelli che hanno familiarità solo con Explorer Windows potrebbero grattarsi la testa e dire "Non va bene!". È vero che IE/Win racchiude automaticamente un float all'interno di un contenitore, ma solo se il contenitore ha una dimensione data. In ogni caso, questa è una violazione delle specifiche del W3C. Questo comportamento errato può anche essere attivato disattivato dai link all'interno del contenitore se lo stato :hover dei link altera il loro sfondo (o anche attraverso altre proprietà). Una bella confusione.

Anche l'Internet Explorer fallito, Opera 7, racchiuderà un float quando il contenitore è dimensionato, ma questo fatto non influenza nessuno degli argomenti a seguire e può essere ignorato in sicurezza, sebbene una risatina sia consentita. ;-)

Il W3C suggerisce di usare un elemento con clear alla fine del box contenitore, il quale viene riconosciuto dal contenitore e lo forza ad includere tale elemento, come descritto in Float: The Theory:

“..supponiamo di dare al box che segue la proprietà 'clear' con  {clear: both;} . Essa estenderà il margine sulla parte superiore del box con clear, spingendolo in basso finchè non ripristina il flusso sotto il float. In altre parole, il margine superiore del box con clear (non importa quale sia la sua impostazione) viene aumentato dal browser della misura necessaria a tenere il box con clear sotto il float. ”

In effetti tale box non può trovarsi sullo stesso livello orizzontale del float che lo precede. Deve comparire sotto tale livello. L'immagine che segue mostra come dovrebbe apparire, con un bordo rosso che rappresenta l'elemento contenitore:

Mostra un box con clear sotto il float.

Il metodo standard per far si che un contenitore esterno sembri "racchiudere" un float consiste nel posizionare un elemento con clear alla fine del contenitore, che ha l'effetto di spostare il limite inferiore del box contenitore più in basso del float. In questo modo il float sembra racchiuso all'interno del contenitore anche se non lo è. Il codice di solito somiglia a qualcosa del genere:


<div><!--contenitore del float-->
<div style="float:left; width:30%">
<p>Del contenuto</p>
</div>
<p>Testo fuori dal float.</p>
<div style="clear: both;"></div>
</div>

Dato che questo div non è flottato, il contenitore deve riconoscerlo e racchiuderlo, e a causa del margine superiore (aggiunto dal browser in seguito alla proprietà 'clear') il div spinge il limite inferiore del contenitore sotto il limite inferiore del float.

Problemi con questo metodo

In primis, questo metodo di clearing non è del tutto intuitivo, e richiede un elemento extra da aggiungere alla marcatura. Una delle maggiori premesse dei CSS è quella di aiutare a ridurre la marcatura HTML in eccesso che affligge di questi tempi un sito medio. Così aumentare la marcatura solo per far stare i float nei loro contenitore non è una soluzione ideale.

A parte questo, alcuni browser possono avere dei problemi con alcuni elementi di clearing in determinate situazioni. Mozilla è particolarmente sensibile ai problemi di clearing.

Fino ad oggi non c'era un altro modo per farlo, ma ora non più! Grazie agli sforzi di Tony Aslett, creatore e sviluppatore di csscreator.com, possiamo usare ora un CSS avanzato per dare il clear ad un contenitore nei browser diversi da IE, e lasciare semplicemente che IE continui a darsi il clear da solo. Il risultato è che ora abbiamo la possibilità di evitare di aggiungere questo fastidioso elemento extra alla marcatura. Woohoo!

Il clearing nel Ventunesimo Secolo

Nel nuovo metodo non si usa nessun elemento di clearing. Questo non influenzerà IE/Win, che continuerà semplicemente a racchiudere il float come sempre (posto che il contenitore abbia una dimensione data), ma nei browser diversi da IE ci sarà bisogno di un sostituto per questo elemento. Ecco come è stato realizzato.

Usare :after

Questa proprietà CSS 2 permette di inserire del contenuto extra alla fine dell'elemento tramite il CSS, il che significa che non c'è bisogno di alcuna marcatura effettiva nell'HTML. Il contenuto viene specificato all'interno del foglio di stile, e compare nella pagina come un reale elemento HTML che segue il normale contenuto dell'elemento di destinazione. Il contenuto generato con :after non può avere alcune proprietà, tra cui 'position', 'float', proprietà degli elenchi e delle tabelle. Tuttavia, la proprietà 'clear' è ammessa. Vedete dove vogliamo arrivare?

Immaginiamo di usare :after per inserire un semplice carattere come un punto, e quindi di dargli {clear: both}. Questo è tutto quello di cui avete bisogno per questo lavoro, ma dato che nessuno vuole una riga vuota alla fine del box contenitore usiamo anche {height: 0;} e {visibility: hidden;} per nascondere il punto.


.clearfix:after {
content: "."; 
display: block; 
height: 0; 
clear: both; 
visibility: hidden;
}

Si noti che viene applicato anche {display: block;} all'elemento :after, perché il suo valore di default è inline, e quindi non può ricevere la proprietà 'clear'. Inoltre il metodo di Tony usava in origine overflow: hidden per nascondere il punto, ma purtroppo le ultime versioni di Firefox mostreranno il punto se lo si usa.

Ed IE?

Dato che IE/Win non supporta lo pseudo-elemento :after dobbiamo affidarci al suo effetto di "auto-clearing", che avviene solo quando l'elemento di clear ha una dimensione. Nella maggior parte dei casi non si vuole usare una larghezza o un'altezza, ma per fortuna l'Holly hack ci viene in aiuto. Questo hack fa vedere solo ad IE/Win una semplice altezza di 1% per il contenitore. Come ci aiuta tutto questo? Bé, succede che IE/Win abbia un'altra violazione delle specifiche per cui tutti i box si espanderanno per includere il contenuto, senza badare alle eventuali dimensioni che possono essere inferiori. In questo modo l'altezza di 1% farà in modo che il box si espanderà quel tanto che basta a contenere il float, e il semplice fatto di applicare una dimensione causa questo comportamento. Fico, vero?


/* Nasconde da IE-mac \*/
* html .clearfix {height: 1%;}
/* Fine dell'hack per IE-mac */

La prima riga è un commento con un escape (in rosso) prima della chiusura del commento. A causa dell'escape, IE/Mac ignora la chiusura del commento e pensa che il commento sia ancora aperto. In questo modo ignora tutto finchè non incontra la chiusura del commento. L'ultima riga è un commento normale, e la sua chiusura fa si che IE/Mac ricominci a leggere il codice.

La seconda riga ha un selettore universale seguito da html (in rosso), seguito dall'elemento di destinazione. Esso seleziona .floatholder se si trova all'interno di html e anche se html è si trova all'interno di qualsiasi altro elemento. Questo accade perché i browser IE hanno un misterioso ed invisibile elemento contenitore intorno ad html, e così questo selettore funziona solo in IE. IE/Mac non deve vedere questa altezza, poiché non allarga il box come IE/Win e questo danneggerebbe il layout.

Come ulteriore beneficio, questa dimensione risolve altri gravi bug nel float di IE/Win. Tuttavia, se questo box contenitore dovesse essere posizionato dopo un float esterno, l'altezza data ad IE innescherà il modello float di Microsoft (proprietario ed errato). State attenti, ok?

Problemi

Bé, succede che IE ha un problemino con questo comportamento di auto-inclusione. Ve ne siete accorti, giusto? Si, i bug di IE vengono proprio a mandrie. Questo si verifica quando il contenitore ha dei link all'interno che seguono il float. Quando si verifica questa condizione, e si passa con il mouse su alcuni link, l'auto-inclusione viene come "disattivata", e il limite inferiore del box contenitore salta all'improvviso oltre la parte inferiore del contenuto non flottato. Passando con il mouse su altri link, la condizione iniziale viene ripristinata. Questo interessante effetto viene detto bug della ghigliottina di IE/Win. Chi sta navigando con IE/Win può divertirsi con i demo che seguono, e per una spiegazione più dettagliata si veda l'articolo corrispondente.

Il problema ricorre solo quando si usa a:hover per cambiare lo sfondo del link o altri stili, come il padding, margin e font del link. Stranamente, cambiare il colore del testo non innesca il bug.

I contenitore sono grigi con bordi verdi, e i float sono marrone scuro con bordi gialli. Notate come il terzo e quarto link fuori dai float attivi il bug, e i primi due lo disattivino. Questo sembra essere correlato con le stesse righe di testo, e così tutti i link dopo le prime due righe attiveranno l'effetto. I link nel float disattiveranno tutti l'effetto. È solo un altro bug di IE gente, nulla di strano.

Screenshot

Il secondo demo è stato "fixato" mettendo questi link in un paragrafo, che poi riceve una dimensione tramite l'Holly hack. Qualsiasi altro elemento di blocco servirebbe allo scopo. Si, questo significa che abbiamo bisogno di un altro elemento, ma a differenza di un div col clear questo è un elemento semantico. Il contenuto testuale dovrebbe essere comunque inserito in contenitori semantici, e dato che noi sviluppatori previdenti organizziamo sempre il nostro contenuto in questo modo, è facile applicare la stessa classe .clearfix a più elementi.

Una parola sui float nei float

I lettori attenti avranno notato che i demo precedenti racchiudono tutti i float, anche in Opera 7 e Mozilla! Questo avviene perchè gli stessi demo sono float, e i browser moderni lasciano sempre che i float racchiudano altri float. Anche IE lo fa, e infatti racchiude erroneamente TUTTI gli elementi (non solo i float). IE non può farlo senza l'Holly hack, ma questa è la realtà. Almeno si può risolvere, cosa che non avviene sempre in IE. IE/Mac ha dei problemi con i float annidati. Se un lettore che usa un Mac farà un test completo sul problema e stenderà un resoconto chiaro, c'è un link di ringraziamento che lo aspetta.

Assemblare il tutto

Per prima cosa si aggiunge questo codice al foglio di stile:


.clearfix:after {
content: "."; 
display: block; 
height: 0; 
clear: both; 
visibility: hidden;
}

/* Nasconde da IE-mac \*/
* html .clearfix {height: 1%;}
/* Fine dell'hack per IE-mac */

Aggiungete solo una classe .clearfix nel sorgente ad ogni elemento che contiene un float a cui applicare il clear, e a tutti gli elementi di blocco che fixano il bug della ghigliottina all'interno del contenitore. Tutto qua! Non è perfetto, ma è sempre meglio che aggiungere un elemento extra.

IE/Mac colpisce ancora

Tutto fantastico, ma purtroppo IE per Mac non da automaticamente il clear ai float, e non supporta :after, e così è fuori dalla festa. Che fare?

Potreste abbandonare senza pietà IE/Mac al suo destino, ma tenete presente che molte persone che usano vecchi Mac non possono installare Safari o altri browser moderni. Per fortuna questo browser è stato abbandonato da Microsoft, e in futuro il numero di questi utenti di IE/Mac diverrà insignificante. Ricordate che anche se un float sporge da un contenitore, nessun contenuto verrà coperto. Non sembrerà bello ai lettori, tutto qua. Ogni autore dovrà prendere una decisione in merito secondo le sue specifiche esigenze.

Questo articolo descriveva un metodo JavaScript per forzare IE/Mac verso la conformità, ma ora grazie a Mark Hadley e Matt Keogh è possibile evitare JavaScript e usare un metodo CSS diretto. Woohoo!

Vincere il problema del float di IE/Mac

In pratica la soluzione consiste solo nell'applicare display: inline-block; alla classe .clearfix, nascondendolo agli altri browser. Tutto qui! Possiamo farlo semplicemente modificando il codice esistente.


.clearfix:after {
content: "."; 
display: block; 
height: 0; 
clear: both; 
visibility: hidden;
}

.clearfix {display: inline-block;}

/* Nasconde da IE-mac \*/
* html .clearfix {height: 1%;}
.clearfix {display: block;}
/* Fine dell'hack per IE-mac */

.clearfix {display: inline-block;} viene visto da tutti i browser, e risolve il problema in IE/Mac. Quindi, all'interno dell'insieme di regole nascosto ad IE/Mac, la proprietà 'display' viene reimpostata su block. Tutto qua! Incollate semplicemente il codice di sopra nel vostro foglio di stile e usate .clearfix su qualunque box contente un float. Non è fico? State solo attenti ai float esterni precedenti che innescano il modello float di IE, come detto in precedenza.

Un grazie a Alex Robinson per aver scoperto che inline-block è migliore del vecchio fix con inline-table per IE/Mac.

Un avvertimento (importante!)

Le specifiche sul float richiedono che un elemento con il clear debba stare sotto tutti i precedenti float. Non ci sono eccezioni! "Precedente" in questo caso significa ogni float che viene prima nel documento sorgente.

Fino al novembre del 2004, Firefox applicava scorrettamente il clear solo ai float che erano verticalmente sopra l'elemento con il clear, invece che a tutti i precedenti float. Ciò voleva dire che nei vecchi browser Gecko potevate posizionare una colonna flottata lungo un lato dello schermo, e all'interno di un altra colonna (possibilmente flottata) potevate dare il clear ad un float interno più piccolo, senza che l'elemento con il clear fuoriuscisse dalla precedente colonna flottata. Poichè solo Gecko aveva questo problema, era ovvio che qualcosa non andava ogni volta che questo si verificava in una pagina. Di solito Gecko è il browser buono, ma in questo caso era l'accusato. Vedete, non sempre IE è quello cattivo!

Tuttavia questo semplice metodo di clearing ha confuso solo un pò il problema, poichè ora Explorer non applica del tutto il clear, mentre i browser Gecko hanno alla fine corretto il problema e danno il clear ai float precedenti.

...Oh no! Vedete ora cosa succederà nella nostra ipotetica pagina? IE, non vedendo nessun reale elemento con il clear, andrà alla grande, mentre nei nuovi browser Gecko e in Opera 7, l'elemento di clear generato nel primo box aumenterà l'altezza del box nella pagina, dato che questo elemento invisibile si trova verticalmente sotto la parte inferiore della precedente colonna flottata (presupponendo che ci sia una parte inferiore!). Questo può creare un ampio spazio vuoto all'interno del box con il clear, a seconda dell'effettiva altezza della vicina colonna flottata.

Naturalmente Opera 7 ha sempre implementato correttamente le specifiche sul clear, come IE (a parte i bug), e i browser per Mac non sono coinvolti. Se vi state chiedendo come possa essere risolto questo problema, bé, non si può. Gecko ed Opera ora seguono correttamente le specifiche, ed IE fallisce solo a causa del falso clearing da noi impostato per lui.

Impedire il clearing esterno

Se avete il problema descritto in precedenza, un modo per impedire che l'elemento con il clear influenzi la colonna flottata adiacente consiste nel rendere il contenitore (ove risiede l'elemento con clear) flottato a sua volta. Se l'elemento con clear si trova all'interno di un contenitore flottato, influenzerà solo i float che lo precedono all'interno di quel contenitore flottato. L'elemento con il clear non uscirà fuori dal suo contenitore flottato per influenzare i float esterni. Inoltre tale elemento non ha effetto sul suo genitore se non quello di fargli racchiudere tutti i float annidati al suo interno.

Ok, questo richiede delle modifiche strutturali, ma meno di quelle che pensate. Infatti quando tutti gli elementi principali in un layout colonnare sono float, i peggiori bug di IE con il float non si verificano. Così un simile approccio al design colonnare può essere di sicuro più facile da ottenere, almeno nell'àmbito di un layout fisso.

Ancora su IE/Mac e i float

Secondo Alex Robinson, inline-block può essere usato sugli elementi di blocco all'interno dei float per impedire ad IE/Mac di espandere a larghezza piena i float senza dimensione. Di solito i float devono avere una larghezza, ma le nuove specifiche consentono l'uso di float privi di dimensione che seguono l'algoritmo "shrink-to-fit". Unico tra i browser moderni, IE/Mac espanderà un float al 100% se il float contiene un elemento di blocco. Bé, date all'elemento annidato inline-block solo per IE/Mac, usando i metodi per nascondere gli stili visti sopra, e i float seguiranno l'algoritmo "shrink-to-fit" in IE/Mac. Doppio woohoo! State solo attenti a non annidare altri elementi di blocco o questi faranno di nuovo espandere il float, e non usate questa tecnica con gli elementi flottati a destra, come ci avverte Philippe Wittenbergh. Grazie per i suggerimenti sul Mac, Alex e Philippe!

A coloro che lo hanno reso possibile

Grazie a Tony Aslett per averci indicato la via. Il suo sito, csscreator.com, è un micidiale forum dove principianti e simil-guru si frequentano per scambiarsi soluzioni per i fogli di stile. Il demo originale di Tony per questo metodo si trova qui, e il thread del forum qui.

Grazie anche a Doug per aver individuato il problema del punto in FireFox, e a Mark Hadley per quell'elegante soluzione per IE/Mac, e a Matt Keogh per aver dimostrato come inline-table risolva il problema in IE/Mac usando al contempo una proprietà CSS già approvata. Ancora una volta la comunità CSS arriva in aiuto di tutti noi! :-)

Torna su