1. 什么是浮动
浮动方式布局就是使用 float
属性,使元素脱离文档流,浮动起来。
浮动元素会脱离文档流并向左/向右浮动,直到碰到父元素或者另一个浮动元素。
1.1 特征
1.1.1 脱离文档流
脱离文档,也就是说浮动不会影响普通元素的布局。即其他div不会被设置浮动的div浮动位置影响,但是文字仍会为被浮动div让位。因为设置浮动的div只脱离了文档流并未脱离文本流。
从上图可以看出,默认三个设置了宽高的block元素,本来会格子独占一行;如果框1设置了向左/向右浮动,他会忽略框2和框3,直到碰到父元素;同时也存在盖住普通元素的风险。
如图所示,其他div在定位时会忽略被浮动div,而文字不会忽略。
1.1.2 可以内联排列
浮动会向左/向右浮动,直到碰到另一个浮动元素为止,这是浮动可以内联排列的特征。也就是说,浮动可以设置宽高,并且能够一行多个,是介于block和inline之间的存在。
1.1.3 会导致父元素高度坍塌
浮动会脱离文档流,这个问题对整个页面布局有很大的影响。
子元素设置浮动,若父元素内部若无其他未设置浮动的元素,切父元素未设置高度,则会出现父元素高度坍塌问题。
我们可通过clear浮动来解决。
1.1.4 案例
<div class="topDiv">
<div class="floatDiv">float left</div>
<div class="textDiv">Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.
</div>
</div>
<div class="bottomDiv">Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.
</div>
.topDiv {
width: 500px;
border: 2px solid black;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
2. 清除浮动
2.1 clear清除浮动
还是开篇的例子,我们给需要清除浮动的元素添加如下样式:
.textDiv {
color: blue;
border: 2px solid blue;
clear: left;
}
原理:
通过上面的样式,.textDiv告诉浏览器,我的左边不允许有浮动的元素存在,请清除掉我左边的浮动元素。然而,因为浮动元素(.floatDiv)位置已经确定,浏览器在计算.textDiv的位置时,为满足其需求,将.textDiv渲染在浮动元素下方,保证了.textDiv左边没有浮动元素。同时可以看出,父元素的高度也被撑起来了,其兄弟元素的渲染也不再受到浮动的影响,这是因为.textDiv仍然在文档流中,它必须在父元素的边界内,父元素只有增加其高度才能达到此目的,可以说是一个意外收获。(clear的值为both也有相同的效果,通俗理解就是,哪边不允许有浮动元素,clear就是对应方向的值,两边都不允许就是both)
但是,如果我们把HTML中的.floatDiv和.textDiv交换一下位置呢?
<div class="topDiv">
<div class="textDiv">Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.
</div>
<div class="floatDiv">float left</div>
</div>
<div class="bottomDiv">Nam vulputate diam nec tempor bibendum. Donec luctus augue eget malesuada ultrices. Phasellus turpis est, posuere sit amet dapibus ut.
</div>
无论.textDiv是否应用清除浮动,情况都是下面的样子:
.textDiv
的位置先确定了,于是浮动元素就紧接着.textDiv
下方渲染在父元素的左侧。然而,父元素的高度并没有被撑起来,没有将浮动影响“内化”,导致浮动影响到了接下来的元素排版。
看来,为达到撑起父元素高度的目的,使用clear
清除浮动的方法还是有适用范围的。我们需要更加通用和可靠的方法。
(这里澄清一下,单从元素清除浮动的角度,clear
完全已经达到了目的,它已经使得.textDiv
特定的方向上不再有浮动元素,清除浮动其实仅仅针对需要清除浮动的元素本身而言,只关注自身需求是否达到,和外界没有什么关系,它不关注浮动是否超出父元素,以及浮动是否影响到后续元素排列。我们只是利用了浮动的一些特性达到某些目的,但这不是清除浮动关心的问题,只不过,相对于清除浮动,我们可能更加关心这些特性能为我们做些什么而已。我的理解是,清除浮动和撑起父元素高度其实是两个不同的问题,在这里,可以简单地理解为工具和目的之间的关系,接下来要讨论的两个方法都是在利用清除浮动这个工具在解决问题,它并不是清除浮动这个工具本身。不过,我们经常将两者混为一谈。)
2.2 父元素结束标签之前插入清楚浮动的块级元素
HTML结构如下,在有浮动的父级元素的末尾插入了一个没有内容的块级元素div:
<div class="topDiv">
<div class="textDiv">...</div>
<div class="floatDiv">float left</div>
<div class="blankDiv"></div>
</div>
<div class="bottomDiv">...</div>
.topDiv {
width: 500px;
border: 2px solid black;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
// 区别在这里
.blankDiv {
clear: both; // or left
}
原理无需多讲,和第一个例子里.textDiv
应用clear
清除浮动,撑起父级元素高度的原理完全一样。这里强调一点,即,在父级元素末尾添加的元素必须是一个块级元素,否则无法撑起父级元素高度。
2.3 利用伪元素
HTML
结构如下,为了惯例相符,在.topDiv
的div
上再添加一个clearfix
类:
<div class="topDiv clearfix">
<div class="textDiv">...</div>
<div class="floatDiv">float left</div>
</div>
<div class="bottomDiv">...</div>
// 省略基本的样式
// 区别在这里
.clearfix:after {
content: '.';
height: 0;
display: block;
clear: both;
}
该样式在clearfix
,即父级元素的最后,添加了一个:after
伪元素,通过清除伪元素的浮动,达到撑起父元素高度的目的。注意到该伪元素的display
值为block
,即,它是一个不可见的块级元素(有的地方使用table
,因为table
也是一个块级元素)。你可能已经意识到,这也只不过是前一种清除浮动方法(添加空白div
)的另一种变形,其底层逻辑也是完全一样的。前面的三种方法,其本质上是一样的。
2.4 利用overflow清除浮动
首先直观地看看,overflow是如何清除浮动的。
<div class="topDiv">
<div class="floatDiv">float left</div>
<div class="textDiv">...</div>
</div>
<div class="bottomDiv">...</div>
.topDiv {
width: 500px;
padding: 4px;
border: 2px solid black;
// 区别在这里
overflow: auto;
}
.floatDiv {
width: 100px;
height: 100px;
border: 2px dotted red;
color: red;
margin: 4px;
float: left;
}
.bottomDiv {
width: 500px;
height: 100px;
margin: 5px 0;
border: 2px dotted black;
}
.textDiv {
color: blue;
border: 2px solid blue;
}
仅仅只在父级元素上添加了一个值为auto
的overflow
属性,父元素的高度立即被撑起,将浮动元素包裹在内。看起来,浮动被清除了,浮动不再会影响到后续元素的渲染(严格讲,这和清除浮动没有一点关系,因为不存在哪个元素的浮动被清除,不纠结这个问题)。其实,这里的overflow
值,还可以是除了"visible"
之外的任何有效值,它们都能达到撑起父元素高度,清除浮动的目的。不过,有的值可能会带来副作用,比如,scroll
值会导致滚动条始终可见,hidden
会使得超出边框部分不可见等。那它们是如何做到浮动清除的呢?
要讲清楚这个解决方案的原理,有一个概念始终是绕不过去,那就是块格式化上下文(BFC
),然而这又是一个非常抽象的概念。这里不多赘述,我们会在另一篇文章中详细的讲解。BFC(Block Formatting Context)