CSS

Empêcher les flottants de dépasser de leur conteneur

Article par (Lyon, France)
Créé le , mis à jour le (215834 lectures)
Tags : css, float, flottant, conteneur, débordement, dépassement, clearfix, clear

Par défaut dans les navigateurs, les éléments positionnés grâce à la propriété CSS float (aussi appelés flottants, ou en anglais floats) sortent du flux de leur conteneur. Autrement dit, les flottants «dépassent». C'est ainsi qu'on se retrouve avec des conteneurs qui font zéro pixel de hauteur, des colonnes qui passent à travers un pied de page, et autres résultats peu souhaitables.

Par exemple, avec ce code HTML et CSS les «colonnes» flottantes dépasseront de leur conteneur:

<div id="conteneur">
  <div class="colonne">AAA</div>
  <div class="colonne">BBB</div>
  <div class="colonne">CCC</div>
</div>
#conteneur {
  height: auto; /* Par défaut. Prend la hauteur du contenu. */
  border: 2px solid red;
}
#conteneur > .colonne {
  width: 33%;
  float: left;
}

Comment bloquer ponctuellement le dépassement des flottants? Il existe plusieurs méthodes. Voici les trois principales, avec pour chacune une mention des principaux avantages et inconvénients, pour obtenir le résultat attendu :

La propriété overflow

La propriété CSS overflow définit comment un bloc doit se comporter lorsqu'un contenu dépasse de ce bloc. Les valeurs possibles sont visible (le contenu dépasse et est visible), hidden (le contenu qui dépasse est masqué), scroll (on affiche systématiquement des barres de défilement pour le bloc) et enfin auto (on affiche des barres de défilement si un contenu dépasse).

Cette propriété a aussi pour caractéristique, lorsqu'on utilise les valeurs autres que visible, de créer ce qu'on appelle un contexte de formatage de bloc. Et une des propriétés des contextes de formatage de bloc, c'est d'empêcher le dépassement des flottants. C'est magique!

Voici comment on peut utiliser overflow pour éviter que les éléments flottants:

#conteneur {
  overflow: hidden; /* Empêche le dépassement des flottants. */
}

Avantage: technique efficace, tient en une ligne.
Inconvénient: lorsqu'on veut faire dépasser certains éléments du conteneur (par exemple un contenu court ou un élément de décoration), le overflow:hidden est gênant car il masque tout ce qui dépasse.

La propriété clear

La propriété CSS clear permet d'indiquer qu'un élément doit venir se placer en dessous des éléments flottants qui le précèdent. Les valeurs possibles sont none (par défaut), left (l'élément passe en dessous des éléments flottant à gauche), right (l'élément passe en dessous des éléments flottant à droite), et both (il passe en dessous de tout les flottants).

Pour bloquer le dépassement des flottants, on peut placer un élément vide juste avant la balise fermante du conteneur, et on lui applique un clear:both;. (Attention, clear n'affecte que les éléments en display:block;, donc on utilisera de préférence un élément div, ou bien on rajoutera un display:block; dans les styles CSS.) En reprenant notre exemple, nous devons modifier le code HTML ainsi:

<div id="conteneur">
  <div class="colonne">…</div>
  <div class="colonne">…</div>
  <div class="colonne">…</div>
  <div class="clear"></div>
</div><--#conteneur-->

Notre code CSS devient:

#conteneur {
  /* Rien de spécial ici. */
}
#conteneur > .clear {
  clear: both;
  height: 0; overflow: hidden; /* Précaution pour IE 7 */
}

Avantage: technique éprouvée, pas ou peu d'effets indésirables.
Inconvénient: il faut ajouter un élément «inutile» dans le code HTML.

Utiliser clear sans modifier le code HTML (clearfix)

Pour finir, voici une variante intéressante de la technique du clear: both;. On peut éviter de rajouter un élément vide dans le code HTML si on simule cet élément directement en CSS. C'est possible en CSS 2.1 grâce à ce que CSS appelle le «contenu généré». On utilisera pour ça le pseudo-élément :after (notons qu'en CSS 3 on écrira ::after, mais cette notation n'est pas comprise de tous les navigateurs actuels).

On repart donc de notre code HTML propre. Rien dans les poches, rien dans les manches:

<div id="conteneur">
  <div class="colonne">…</div>
  <div class="colonne">…</div>
  <div class="colonne">…</div>
</div><--#conteneur-->

Et en CSS, on va générer un pseudo-élément qui va se rajouter à la fin de notre conteneur:

#conteneur {
  /* Rien de spécial ici. */
}
#conteneur:after {
  content: ""; /* Important, sinon l'élément n'est pas généré. */
  display: table;
  clear: both;
}

Avantage: pas d'élément rajouté dans le HTML, et pas ou peu d'effets indésirables.
Inconvénient: en inspectant une page avec les outils pour développeur (Firebug, Web Inspector, etc.), les pseudo-éléments ne sont pas visibles. Sans relire le fichier CSS lui-même, on ne peut pas savoir que cette technique est utilisée. Enfin, cette technique est compatible avec tous les navigateurs récents (dont IE 8), mais pas avec IE 7.

Le cas IE 7… voire IE 6

Toutes les techniques proposées sont compatibles avec toutes les versions récentes des navigateurs (en comptant IE8 dans les versions récentes). Par contre, certaines techniques ne sont pas compatibles avec IE 7 ou IE 6. Je récapitule, par compatibilité décroissante:

  • div vide en clear:both, compatible IE 7 et IE 6;
  • overflow:hidden, compatible IE 7 mais pas IE 6;
  • pseudo-élément :after en clear:both, à partir d'IE 8 uniquement.

Une première solution pour le problème IE 6-7 c'est de choisir une technique compatible. Une autre solution c'est d'utiliser, en complément de ces techniques, le hasLayout — un comportement spécifique aux anciennes versions d'Internet Explorer (avant IE 8), qui a aussi pour caractéristique de bloquer le dépassement des flottants.

En gardant le même code HTML, la technique à base de overflow:hidden devient:

#conteneur {
  overflow: hidden; /* Empêche le dépassement des flottants. */
  zoom: 1; /* Idem pour IE 6-7 (active l'état "hasLayout") */
}

Et la technique du pseudo-élément :after devient:

#conteneur {
  zoom: 1; /* "hasLayout", empêche le dépassement
              des flottants dans IE 6-7 */
}
#conteneur:after {
  content: "";
  display: table;
  clear: both;
}

L'état hasLayout peut aussi, dans certaines circonstances particulières, causer des bugs de rendu… ou au contraire en corriger certains. Pour toute personne qui travaille sur du code CSS destiné aux anciennes versions d'Internet Explorer (avant IE 8), il est indispensable de lire HasLayout et bugs de rendu dans Internet Explorer 6-7.

Ressources

Commentaires

ThomasB a dit le

Bon article.
Je voudrais juste ajouter qu'utiliser uniquement :after{} (cf. dernier cas) pose un problème pour la gestion de la fusion des marges, cf. How to "patch" clearfix so it can better handle collapsing margins.
Sinon, le Web Inspector de Chrome 10 beta (voire des versions avant) montre les pseudo-éléments. Pour Firebug, ils dépendent malheureusement d'un bug de Firefox.

mrpx a dit le

Une chose importante également : Si le parent d'un élément en float est également en float, il prendra en compte les dimensions de son enfant.
Pas forcément à prescrire dans tous les cas, mais cette astuce m'a permis de me dégager de l'astuce clear:both citée dans l'article.
Elle est aussi à la base du 3 colonnes magique : http://matthewjamestaylor.com/blog/perfect-3-...

fvsch a dit le

@mrpx, Je ne suis vraiment pas fan de cette solution. Un peu plus subtil, on peut utiliser display:table ou encore display:inline-block pour bloquer le dépassement des flottants (compatible IE8). Mais je trouve que ces solutions ont des effets secondaires importants (float, display:table ou display:inline-block ont pas mal de caractéristiques propres), et plus difficiles à assimiler que le simple overflow:hidden. Je recommande donc overflow:hidden, et éventuellement un clear:both (avec un div vide ou un :after, suivant quels navigateurs on doit supporter). Et là, je crois qu'on a fait le tour.

webetcaetera a dit le

Quelle différence entre "#conteneur:after" et la bonne vielle méthode du ".clearfix" pré-défini ? (si ce n'est une classe de moins, mais qui peut également économiser des déclarations de "x #conteneur:after" )

fvsch a dit le

@webetcaetera C’est la même méthode. Je présente la manière dont la méthode fonctionne, avec un exemple simple. Ensuite, l'utilisation d'une classe unique est un détail d'implémentation.

webetcaetera a dit le

Ok, merci, je pensais que quelque chose m' avait échappé.
Toutes ces méthodes sont utiles, et utilisables en fonction du contexte 1 article de Romy Têtue et des commentaires intéressants sur le sujet : http://romy.tetue.net/espaceurs-de-blocs .
J'aime bien l' utilisation du "br class=clear" simple et souvent suffisant.

DvN a dit le

@fvsch j'admire vos articles et vos réactions sur le forum / site. Voilà c'est tout;0))

Raphael a dit le

@jb_gfx : hello, je ne comprends pas vraiment ton commentaire. Tu voudrais bien en dire un peu plus ? Préciser au-moins le fond de ta pensée ?

Julien Royer a dit le

Merci Florent, voilà une référence pour ce sujet essentiel mais souvent méconnu.

Identity62 a dit le

Oui, mais un overflow:auto sur le conteneur des éléments flottants, règle tout...
Je ne comprends pas comment ça n'a pas pu être mentionné dans cet article o.O

Et c'est pas nouveau...

Laurie-Anne a dit le

Identity62 > Overflow:auto ou overflow:hidden, revient au même (pour le sujet en question) ; et c'est la première solution donnée dans l'article.

Raphael a dit le

@Identity62 : il a été mentionné mais je pense que tu as dû survoler l'article.
Overflow : auto affiche des barres de défilement dès qu'un contenu dépasse... et ça arrive bien plus souvent qu'on ne le croit (commentaires d'utilisateurs, mots longs, infobulles, éléments dynamiques tels que des menus déroulants, etc.). Je me rappelle l'avoir haï pour ça très récemment.

Squal38 a dit le

Dans un précédent article sur le sujet sur Alsacreations, je suis à peu près sur que pour la technique du ":after" vous disiez que c'était valable pour IE >= 7 (ou plutôt que ça ne marchait pas dans IE<7). Je n'arrive plus à retrouver l'article mais peut-on avoir une confirmation sur la version d'IE à partir de laquelle ça marche ?
Merci

fvsch a dit le

@Squal38 : Le contenu généré (pseudo-élément :after, propriété content) est spécifié en CSS 2.1, et supporté à partir d'IE8. Pas dans IE7.

JackNUMBER a dit le

Merci merci merci merci merci !
Je cherche un hack comme ça depuis pas mal de temps.

Raphael a dit le

@jb_gfx : disons que la technique basée sur :after (nommée généralement clearfix) a fait - je crois - son apparition via Paul Irish l'an passé et cela ne fait pas si longtemps que son adaptation pour fonctionner sous IE7 et IE6 est robuste.
De plus, même si les idées ne sont pas forcément avant-gardistes, elles demeurent suffisamment pertinentes pour gagner le statut d'article pérenne sur Alsacréations. La preuve est bien que pas mal de membres ignoraient ces techniques car tout le monde n'a pas notre chance de pouvoir faire de la veille technologique poussée.

Toujours est-il que je rappelle qu'Alsa ne vit que par les propositions de ses membres et que toute proposition est bonne à prendre... les tiennes également ;)

fvsch a dit le

Pour répondre brièvement: c’est un article pédagogique qui traite d’un concept de base en CSS. Ça répond aux besoins d'un public important: débutants qui ne connaissent pas le sujet, niveaux intermédiaires qui veulent réviser ou remettre de l’ordre dans leurs idées. C’est une approche non exclusive (on a aussi des articles pour niveau avancé), qui est loin d’être nouvelle sur Alsacréations.

Raphael a dit le

@jb_gfx : ah merci pour l'info. Quand je disais que c'était pas si connu que ça par le grand public :)

polpaulin a dit le

il vaut mieux pas utiliser les float si on peut éviter mais display:table et tout ce qui va avec , en faisant une feuille de style a part pour IE7
ou encore mieux les template layout avec jQuery

jiber2fr a dit le

Je viens de constater que si le parent est en position:absolute, le contenu en float fait le fait grossir autant que nécessaire. (En d'autres termes, le contenu flottant dans un bloc positionné en absolu fait grandir le-dit bloc, et ne dépasse pas). Est-ce un comportement normal, ou bien aie-je raté quelque chose ?