Éléments flottants à l'intérieur d'un div, flottent à l'extérieur de div. Pourquoi?

274

Disons que vous en avez un div, donnez-lui une définition widthet mettez-y des éléments, dans mon cas un imget un autre div.

L'idée est que le contenu du conteneur diventraînera l' divétirement du conteneur et constituera un arrière-plan pour le contenu. Mais quand je fais cela, le contenant divrétrécit pour s'adapter aux objets non flottants, et les objets flottants seront soit complètement sortis, soit à moitié sortis, à moitié entrés, et n'auront aucune incidence sur la taille du grand div.

Pourquoi est-ce? Y a-t-il quelque chose qui me manque, et comment puis-je obtenir des éléments flottants pour étirer le heightcontenant div?

DavidR
la source

Réponses:

398

Le plus simple est de mettre overflow:hiddenle div parent et de ne pas spécifier de hauteur:

#parent { overflow: hidden }

Une autre façon consiste à faire flotter également le div parent:

#parent { float: left; width: 100% }

Une autre façon utilise un élément clair:

<div class="parent">
   <img class="floated_child" src="..." />
   <span class="clear"></span>
</div>

CSS

span.clear { clear: left; display: block; }
Doug Neiner
la source
17
Cela fonctionne, mais maintenant je suis deux fois plus confus: y a-t-il une explication à cela ou est-ce juste comme ça?
DavidR
8
Oui, il y a une explication mais je l'ai depuis oublié :( C'est exactement comme ça. Le overflow:hiddennavigateur force le mieux qu'il peut à contenir les éléments enfants du parent. C'est pourquoi il le corrige.
Doug Neiner
5
Je pense que l'explication overflow: hiddenest ici: lien . Et merci beaucoup, cela a fonctionné pour moi
Vikas Arora
6
@DavidR L'explication la plus simple est que html / css est une technologie datée, mal pensée et mal implémentée. En fait, ce raisonnement explique en fait beaucoup de bizarreries html / css que vous avez sans doute rencontrées depuis que vous avez écrit ce post.
léger
1
Gardez à l'esprit que overflow: hiddencela ne fera que masquer toute partie d'un élément qui sort du conteneur parent. Pour moi, cela a rendu certains morceaux de texte illisibles.
Top Cat
160

Raison

Le problème est que les éléments flottants sont hors du flux :

Un élément est appelé hors flux s'il est flottant, absolument positionné ou s'il est l'élément racine.

Par conséquent, ils ne touchent pas des éléments entourant comme en flux élément serait.

Ceci est expliqué dans 9.5 Flotteurs :

Puisqu'un flottant n'est pas dans le flux, les blocs de blocs non positionnés créés avant et après le flotteur circulent verticalement comme si le flotteur n'existait pas. Cependant, les zones de ligne actuelles et suivantes créées à côté du flottant sont raccourcies si nécessaire pour faire de la place à la zone de marge du flottant.

entrez la description de l'image ici

Ceci est également spécifié dans 10.6 Calcul des hauteurs et des marges . Pour les blocs "normaux" ,

Seuls les enfants dans le flux normal sont pris en compte (c'est-à-dire que les boîtes flottantes et les boîtes absolument positionnées sont ignorées […])

entrez la description de l'image ici

Solution Hacky: dégagement

Un moyen de résoudre le problème consiste à forcer certains éléments entrants à être placés sous tous les flotteurs. Ensuite, la hauteur du parent augmentera pour envelopper cet élément (et donc les flotteurs aussi).

Ceci peut être réalisé en utilisant la clearpropriété :

Cette propriété indique quels côtés de la ou des boîtes d'un élément ne peuvent pas être adjacents à une boîte flottante antérieure.

entrez la description de l'image ici

Donc, une solution consiste à ajouter un élément vide avec clear: bothcomme dernier frère des flotteurs

<div style="clear: both"></div>

Cependant, ce n'est pas sémantique. Mieux vaut donc générer un pseudo-élément à la fin du parent:

.clearfix::after {
  clear: both;
  display: block;
}

Il existe plusieurs variantes de cette approche, par exemple en utilisant la syntaxe :afterà deux points obsolète pour prendre en charge les anciens navigateurs, ou en utilisant d'autres affichages au niveau du bloc comme display: table.

Solution: racines BFC

Il existe une exception au comportement problématique défini au début: si un élément de bloc établit un contexte de formatage de bloc (est une racine BFC), il encapsulera également son contenu flottant.

Selon les hauteurs 10.6.7 «Auto» pour les racines de contexte de formatage de bloc ,

Si l'élément a des descendants flottants dont le bord de marge inférieur est en dessous du bord de contenu inférieur de l'élément, la hauteur est augmentée pour inclure ces bords.

entrez la description de l'image ici

De plus, comme expliqué dans 9.5 Floats , les racines BFC sont également utiles pour les raisons suivantes:

La zone de bordure d'une table, un élément remplacé au niveau du bloc ou un élément dans le flux normal qui établit un nouveau contexte de mise en forme de bloc […] ne doit pas chevaucher la zone de marge des flottants dans le même contexte de mise en forme de bloc que l'élément lui-même .

entrez la description de l'image ici

Un contexte de formatage de bloc est établi par

  • Boîtes de bloc avec overflowautre que visible, par exemplehidden

    .bfc-root {
      overflow: hidden;
      /* display: block; */
    }
    
  • Bloquer les conteneurs qui ne sont pas des blocs: lorsque displayest défini sur inline-block, table-cellou table-caption.

    .bfc-root {
      display: inline-block;
    }
    
  • Éléments flottants: quand floatest réglé sur leftou right.

    .bfc-root {
      float: left;
    }
    
  • Éléments positionnés de manière absolue: quand positionest réglé sur absoluteou fixed.

    .bfc-root {
      position: absolute;
    }
    

Notez que ceux-ci peuvent avoir des effets collatéraux indésirables, comme l'écrêtage du contenu débordant, le calcul des largeurs automatiques avec l' algorithme de rétrécissement pour s'adapter ou devenir hors du flux. Le problème est donc qu'il n'est pas possible d'avoir un élément de niveau bloc en flux avec débordement visible qui établit un BFC.

L'affichage L3 résout ces problèmes:

Création des types d'affichage interneflow et pour mieux exprimer les types d'affichage de disposition de flux et pour créer un commutateur explicite pour faire d'un élément une racine BFC . (Cela devrait éliminer le besoin de hacks comme et […])flow-root ::after { clear: both; }overflow: hidden

Malheureusement, il n'y a pas encore de support de navigateur. Nous pourrons éventuellement utiliser

.bfc-root {
  display: flow-root;
}
Oriol
la source
1
Les boîtes flottantes ne sont donc pas reconnues par leurs conteneurs parents, d'où l'effondrement de la hauteur, mais sont reconnues par leurs frères et sœurs, d'où le clearfix?
symlink
@symlink Oui, les conteneurs parents ne grandissent pas pour contenir des flottants, sauf s'ils sont des racines BFC. Les frères et sœurs qui ne sont pas des racines BFC ne sont pas directement affectés par les blocs (mais leurs boîtes de ligne le sont). Cependant, le dégagement les déplace au-dessous de tout flotteur précédent.
Oriol
"Les frères et sœurs qui ne sont pas des racines BFC ne sont pas directement affectés par les blocs (mais leurs boîtes de ligne le sont)." - Pouvez-vous clarifier cela s'il vous plaît? Voulez-vous dire que dans ce jsFiddle: jsfiddle.net/aggL3Lk7/2 , l'image flottante en ligne n'affecte pas la plage (d'où la bordure de la plage la sous-jacent) mais l'image affecte le texte (qui est la zone de ligne) comme indiqué par le fait que le texte ne sous-estime pas l'image?
symlink
1
@symlink Oui, exactement. Eh bien, dans votre violon, la bordure appartient au parent, mais ce serait fondamentalement la même chose pour les frères et sœurs: jsfiddle.net/aggL3Lk7/3
Oriol
1
Je suis d'accord. Ce devrait être la réponse acceptée. Il est intéressant pour moi que le W3 appelle la façon dont nous sommes obligés de coder un "hack". Quelqu'un a foiré.
DR01D
11

Il ne manque rien. Float a été conçu pour le cas où vous souhaitez qu'une image (par exemple) se trouve à côté de plusieurs paragraphes de texte, de sorte que le texte circule autour de l'image. Cela ne se produirait pas si le texte «étirait» le conteneur. Votre premier paragraphe se terminerait, puis votre paragraphe suivant commencerait sous l'image (peut-être plusieurs centaines de pixels ci-dessous).

Et c'est pourquoi vous obtenez le résultat que vous êtes.

Lucas Wilson-Richter
la source
3
Comment cela a-t-il quelque chose à voir avec l'élément flottant qui étire correctement la hauteur du parent?
léger
11

Dans certains cas, c'est- à- dire lorsque (si) vous utilisez simplement floatpour que les éléments circulent sur la même "ligne", vous pouvez utiliser

display: inline-block;

au lieu de

float: left;

Sinon, l'utilisation d'un clearélément à la fin fonctionne, même si cela peut aller à contre-courant d'avoir besoin d'un élément pour faire ce qui devrait être du travail CSS.

LSerni
la source
11

Voici une approche plus moderne:

.parent {display: flow-root;} 

Plus de corrections claires.

ps Utilisation du débordement: caché; cache l'ombre de la boîte donc ...

en attente de Firefox
la source
Fonctionne également dans Safari 11
attente de Firefox
7

Merci LSerni vous l'avez résolu pour moi.

Pour y parvenir:

+-----------------------------------------+
| +-------+                     +-------+ |
| | Text1 |                     | Text1 | |
| +-------+                     +-------+ |
|+----------------------------------------+

Tu dois faire ca :

<div style="overflow:auto">
    <div style="display:inline-block;float:left"> Text1 </div>
    <div style="display:inline-block;float:right"> Text2 </div>
</div>
Flyout91
la source
4

Comme le dit Lucas, ce que vous décrivez est le comportement prévu pour la propriété float. Ce qui déroute beaucoup de gens, c'est que float a été poussé bien au-delà de son utilisation initiale afin de combler les lacunes du modèle de disposition CSS.

Jetez un oeil à Floatutorial si vous souhaitez mieux comprendre le fonctionnement de cette propriété.

Sam Murray-Sutton
la source
0

Vous pouvez facilement faire avec d'abord vous pouvez faire le div flex et appliquer justifier le contenu à droite ou à gauche et votre problème est résolu.

<div style="display: flex;padding-bottom: 8px;justify-content: flex-end;">
					<button style="font-weight: bold;outline: none;background-color: #2764ff;border-radius: 3px;margin-left: 12px;border: none;padding: 3px 6px;color: white;text-align: center;font-family: 'Open Sans', sans-serif;text-decoration: none;margin-right: 14px;">Sense</button>
				</div>

Vijay Tiwari
la source