在 div 中浮动的元素,为什么会漂浮在 div 外面?

325
假设您有一个 div,给它一个确定的 width 并在其中放置元素,例如一个 img 和另一个 div
这样做的想法是容器 div 的内容会导致容器 div 扩展,成为内容的背景。但当我这样做时,包含的 div 会因非浮动对象而缩小,并且浮动对象要么全部退出,要么一半退出,一半进入,并且不对大 div 的尺寸产生任何影响。
为什么会这样?我错过了什么,如何让浮动项目拉伸包含 divheight
11个回答

464

最简单的方法是在父div上加上overflow:hidden,不要指定高度:

#parent { overflow: hidden }

另一种方法是同时浮动父级div:

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

另一种方法是使用一个清除元素:

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

CSS

span.clear { clear: left; display: block; }

23
可以运行,但现在我更加困惑了:这是有解释还是就是这样子的? - DavidR
10
是的,有一个解释,但我已经忘记了 :( 这就是事实。overflow:hidden会尽最大努力强制浏览器包含父元素的子元素。这就是为什么它可以修复问题。 - Doug Neiner
6
我认为overflow: hidden的解释在这里:链接。非常感谢,它对我有用。 - Vikas Arora
7
html/css 是一种过时、设计不良、实现也不太好的技术,这是最简单的解释。事实上,这个理由可以解释你在发帖后遇到的很多 html/css 怪癖。 - Slight
4
请记住,overflow: hidden 只会隐藏流出父容器的元素部分。对我来说,这导致某些文本变得无法阅读。 - Top Cat
显示剩余5条评论

188

原因

问题在于浮动元素是脱离文档流的:

如果一个元素浮动、绝对定位或者是根元素,那么它就被称为脱离文档流

因此,它们不像行内元素那样影响周围的元素。

这在9.5 浮动中有解释:

由于浮动元素不在文档流中,所以在浮动框之前和之后创建的非定位块级盒子会垂直地流动,就好像浮动元素不存在一样。但是,与浮动元素相邻的当前和随后的行级盒子会缩短,以便为浮动元素的边距盒留出空间。

enter image description here

html {
  width: 550px;
  border: 1px solid;
}
body {
  font-family: sans-serif;
  color: rgba(0,0,0,.15);
}
body:after {
  content: '';
  display: block;
  clear: both;
}
div {
  position: relative;
}
div:after {
  font-size: 200%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
}
.block-sibling {
  border: 3px solid green;
}
.block-sibling:after {
  content: 'Block sibling';
  color: green;
}
.float {
  float: left;
  border: 3px solid red;
  height: 90px;
  width: 150px;
  z-index: 1;
}
.float:after {
  content: 'Float';
  color: red;
}
<div class="float"></div>
<div class="block-sibling">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur. Donec ut libero sed arcu vehicula ultricies a non tortor.
</div>

这也在10.6计算高度和边距中有所说明。对于"正常"块,

只有正常流中的子元素会被考虑进去(即浮动框和绝对定位框将被忽略[...]

enter image description here

html {
  width: 550px;
  border: 1px solid;
}
body {
  font-family: sans-serif;
  color: rgba(0,0,0,.15);
}
body:after {
  content: '';
  display: block;
  clear: both;
}
div {
  position: relative;
}
div:after {
  font-size: 200%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
}
.block-parent {
  border: 3px solid blue;
}
.block-parent:after {
  content: 'Block parent';
  color: blue;
}
.float {
  float: left;
  border: 3px solid red;
  height: 130px;
  width: 150px;
}
.float:after {
  content: 'Float';
  color: red;
}
<div class="block-parent">
  <div class="float"></div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit.
</div>

妙招:清除浮动

解决问题的方法是强制某些内联元素放置在所有浮动元素下方。然后,父元素的高度将增长以包裹该元素(因此也包裹了浮动元素)。

可以使用 clear 属性来实现:

此属性指示元素框的哪些边缘可能与之前的浮动框相邻。

enter image description here

html {
  width: 550px;
  border: 1px solid;
}
body {
  font-family: sans-serif;
  color: rgba(0,0,0,.15);
}
body:after {
  content: '';
  display: block;
  clear: both;
}
div {
  position: relative;
}
div:after {
  font-size: 200%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
}
.block-parent {
  border: 3px solid blue;
}
.block-parent:after {
  content: 'Block parent';
  color: blue;
}
.float {
  float: left;
  border: 3px solid red;
  height: 84px;
  width: 150px;
}
.float:after {
  content: 'Float';
  color: red;
}
.clear {
  clear: both;
  text-align: center;
  height: 37px;
  border: 3px dashed pink;
}
.clear:after {
  position: static;
  content: 'Block sibling with clearance';
  color: pink;
}
<div class="block-parent">
  <div class="float"></div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra.
  <div class="clear"></div>
</div>

因此,解决方案是在浮动元素的最后一个兄弟元素后添加一个具有clear: both属性的空元素。

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

然而,这不是语义化的。因此最好在父元素末尾生成一个伪元素

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

这种方法有多个变体,例如使用已弃用的单冒号语法:after来支持旧版浏览器,或使用其他块级显示方式,如display: table
解决方案:BFC根
在开头定义的问题行为中有一个例外:如果块元素建立了块级格式化上下文(是BFC根),那么它也会包装其浮动内容。
根据10.6.7“自动”高度的块级格式化上下文根

如果该元素具有任何浮动后代,其底部边缘低于元素的底部内容边缘,则将增加高度以包括这些边缘。

enter image description here

html {
  width: 550px;
  border: 1px solid;
}
body {
  font-family: sans-serif;
  color: rgba(0,0,0,.15);
}
body:after {
  content: '';
  display: block;
  clear: both;
}
div {
  position: relative;
}
div:after {
  font-size: 200%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
}
.block-parent {
  border: 3px solid blue;
}
.block-parent.bfc-root:after {
  content: 'BFC parent';
  color: blue;
}
.float {
  float: left;
  border: 3px solid red;
  height: 127px;
  width: 150px;
}
.float:after {
  content: 'Float';
  color: red;
}
.bfc-root {
  overflow: hidden;
}
<div class="block-parent bfc-root">
  <div class="float"></div>
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit.
</div>

此外,正如9.5浮动所解释的那样,BFC根据以下原因也非常有用:

表格的边框盒子、块级替换元素或在正常流中建立新块格式化上下文的元素[...]不得与同一块格式化上下文中任何浮动元素的外边距框重叠。

enter image description here

html {
  width: 550px;
  border: 1px solid;
}
body {
  font-family: sans-serif;
  color: rgba(0,0,0,.15);
}
body:after {
  content: '';
  display: block;
  clear: both;
}
div {
  position: relative;
}
div:after {
  font-size: 200%;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  text-align: center;
}
.block-sibling {
  border: 3px solid green;
}
.block-sibling.bfc-root:after {
  content: 'BFC sibling';
  color: green;
}
.float {
  float: left;
  border: 3px solid red;
  height: 90px;
  width: 150px;
  z-index: 1;
}
.float:after {
  content: 'Float';
  color: red;
}
.bfc-root {
  overflow: hidden;
}
<div class="float"></div>
<div class="block-sibling bfc-root">
  Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec a diam lectus. Sed sit amet ipsum mauris. Maecenas congue ligula ac quam viverra nec consectetur ante hendrerit. Donec et mollis dolor. Praesent et diam eget libero egestas mattis sit amet vitae augue. Nam tincidunt congue enim, ut porta lorem lacinia consectetur.
</div>

一个块级格式化上下文是由什么建立的
  • Block boxes with overflow other than visible, e.g. hidden

    .bfc-root {
      overflow: hidden;
      /* display: block; */
    }
    
  • Block containers that are not block boxes: when display is set to inline-block, table-cell or table-caption.

    .bfc-root {
      display: inline-block;
    }
    
  • Floating elements: when float is set to left or right.

    .bfc-root {
      float: left;
    }
    
  • Absolutely positioned elements: when position is set to absolute or fixed.

    .bfc-root {
      position: absolute;
    }
    
请注意,这些可能会产生不良的副作用,例如剪切溢出内容、使用收缩适应算法计算自动宽度,或者变得失去流程。因此问题在于,不可能拥有一个可见溢出的内联块级元素来建立BFC。 Display L3 解决了这些问题:

创建了 flowflow-root 内部显示类型,以更好地表示流动布局显示类型并创建一个显式开关,使元素成为BFC根。 (这应该消除了像::after {clear:both;}overflow:hidden之类的hack的需求[...]

不幸的是,目前还没有浏览器支持。最终我们可能能够使用。

.bfc-root {
  display: flow-root;
}

1
浮动框不会被其父容器识别,因此高度会塌陷,但是会被它们的同级元素识别,所以要使用clearfix? - symlink
@symlink 是的,父容器不会自动增长以包含浮动元素,除非它们是BFC根元素。不是BFC根元素的兄弟元素不会直接受到块级元素的影响(但它们的行框可能会)。然而,清除属性可以将它们移动到之前的任何浮动元素下方。 - Oriol
“不是 BFC 根的兄弟元素不会直接受到块级格式化上下文的影响(但它们的行盒可能会受到影响)。" - 请您可以澄清一下吗?您的意思是在这个 jsFiddle 中:https://jsfiddle.net/aggL3Lk7/2/,浮动的内联图片不会影响 span 元素(因此 span 的边框会在其之下),但是图片会影响文本(即行盒),这也就是为什么文本没有遮挡图片的原因? - symlink
1
@symlink 是的,完全正确。在你的fiddle中,边框属于父元素,但对于兄弟元素来说基本上是一样的:https://jsfiddle.net/aggL3Lk7/3/ - Oriol
1
我同意。这应该是被接受的答案。有趣的是,W3将我们被迫编写的方式称为“hack”。某人犯了严重错误。 - DR01D
更新2021年:display: flow-root;现在可以使用了,至少在Firefox和Chrome中似乎得到了支持。也许需要更新答案。 - Capstone

25

这里是更现代的方法:

.parent {display: flow-root;} 

不再需要clearfix。

p.s. 使用overflow: hidden;会隐藏box-shadow,因此请注意...


同样适用于Safari 11。 - pendingfox

23

将您的浮动

放在一个
中,并在CSS中为其设置 overflow:hidden;,这样它就可以正常工作了。


我尝试过了,但它并没有解决我的问题:http://stackoverflow.com/questions/25329349/how-to-align-div-inside-another-div?noredirect=1#comment39486464_25329349 - SearchForKnowledge

23

13

谢谢LSerni,你为我解决了这个问题。

要实现这个:

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

你必须这样做:

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

简洁、明了、并且得票不多! - Maurice Klimek

12

在某些情况下,即如果你只是使用float来使元素在同一“行”上流动时,你可能会使用

display: inline-block;

取代

float: left;
否则,即使这可能违背需要一个元素来完成本应由CSS完成的工作的情感,但在末尾使用清除元素也是可行的。

10

没有什么遗漏。float是为了让你在文本段落旁边放置一张图片等元素,使得文字会围绕在图片周围,如果文字“拉伸”了容器的话,这种情况就无法发生了。第一个段落结束后,下一个段落才会在图片下方开始(可能会有几百个像素的空隙)。

这就是你得到当前结果的原因。


3
这与浮动元素如何正确地撑开父容器的高度有什么关系? - Slight

5

正如Lucas所说,你所描述的是浮动属性的预期行为。许多人感到困惑的是,为了弥补CSS布局模型的缺陷,float已经被推得远远超出了其最初的预期用途。

如果您想更好地了解此属性的工作原理,请查看Floatutorial


0
这里的其他解决方案对我没用——我的元素一直被裁剪。但如果其他人在使用bootstrap时遇到相同问题,可以将中间行div的X轴边距明确设置为零,并设置justify-content-between:
<div class='container p-2'>
  <div class='row mx-0 justify-content-between'>
    <div class='float-left'></div>
    <div class='float-right'></div>
  </div>
</div>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接