首页 > 代码库 > 关于浮动和清除浮动
关于浮动和清除浮动
页面布局常用的方式有两种,浮动(float)和定位(position),定位已经讲过了(关于position定位及z-index的理解),这篇主要讲浮动,而浮动和清理浮动是成对出现的,所以也一并讲了。
理解浮动前,我们需要一些前置条件:1. 盒模型; 2. 文档流;
1. 盒模型
一个元素的width或者height属性和它的实际宽度或高度是一致的吗?当然不是,我们看下盒模型就知道了。
css盒模型具备4大属性: content(内容),padding(填充),border(边框),margin(边界)。
我 们可以这样来理解,把它想象成一台彩电。里面的彩电就是content(内容),防震的泡沫塑料就是padding(填充),外面的纸盒子就是 border(边框),彩电存放在库房的时候不能挤压,每个之间要有一定的空隙通风,这个空隙就是margin(边界),width和height就相当 于彩电的宽和高(只是拿来举例子加强理解,不要太较真哦,呵呵)。
那么我们计算一个库房能放多少彩电怎么算?只计算彩电的宽(width)和高(height)吗?肯定不是,一台彩电的占地面积除了彩电自身的宽(width)和高(height)外,还要加上泡沫塑料的厚度(padding),纸盒子的厚度(border),彩电与彩电之间的空隙(margin)。如下图:
所以一个元素的实际占据空间大小应该这样计算:
boxWidth = margin-left + border-left + padding-left + width + padding-right + border-right + margin-right;
boxHeight= margin-top + border-top + padding-top + height + padding-bottom + border-bottom + margin-bottom ;
OK,盒模型到此结束。
2. 文档流(可参考 关于position定位及z-index的理解中的前半部分)
浮动元素也会脱离文档流。
开始浮动的讲解:
先来个例子:
css:
#box {
width: 500px;
border: 1px solid #d9d9d9;
}
#left {
width: 200px;
height: 150px;
background: #54c9e8;
}
#right {
width: 300px;
height: 150px;
background: #e678cc;
}
html:
<div id="box">
<div id="left"></div>
<div id="right"></div>
</div>
效果如图:
我们并没有给任何一个元素添加float属性,默认显示块级元素独占一行(关于块级元素,行内块,行内元素此篇不做详细解释,会在之后另外介绍)。#box(灰线区)没有设置height属性,但是默认会随着内容的高度变化而变化。
当我们给#left(蓝色区)设置 float: left;时,效果如下图:
我们发现#left(蓝色区)向左浮动后,挡在了#right(红色区)上面,前面我们也了解了,浮动的元素是脱离文档流的,所以#right(红色区)占据了#left(蓝色区)原先的位置,与#left(蓝色区)重叠。
如果我们让#right(红色区)也向左浮动,那么会产生下面这种现象,如图:
#left(蓝色区)和#right(红色区)在一行了,这就是我们想要的效果,将两个块级元素放在同一行,但是等等,似乎还有点问题,框呢?我们的#box(灰线区)怎么成一根线了?回味一下我们刚才所理解的:浮动元素脱离文档流。明白了么?虽然#left(蓝色区)和#right(红色区)都是#box(灰线框)的子元素,但是两个都用了 float: left; 进行左浮动,脱离了文档流,原来的#box(灰线区)相当于空了,块级元素默认宽度100%,高度0,所以产生#box(灰线区)没有高度,border-top和border-bottom贴在一起的现象。不仅父元素会受影响,后面的其他元素也可能会受影响。
在解决这个问题前,我们需要了解关于浮动的定义:
浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。由于浮动框不在文档的普通流中,所以文档的普通流中的块框表现得就像浮动框不存在一样。
好了,可以着手解决问题了。解决的方式有两种,一种是让它们都浮起来,这样大家都脱离文档流,都在一个层上了,自然就没问题了。另一种是清理掉浮动(clear)。
第一种:#box(灰线区)浮起来
给#box增加float: left;属性
第二种:清理浮动
我们增加一个.clear的class,在#right(红色区)后面增加一个空div并且使用clear。更改后代码如下:
css:
#box {
width: 500px;
border: 1px solid #d9d9d9;
}
#left {
float: left;
width: 200px;
height: 150px;
background: #54c9e8;
}
#right {
float: left;
width: 250px;
height: 150px;
background: #e678cc;
}
.clear {
clear: both;
}
html:
<div id="box">
<div id="left"></div>
<div id="right"></div>
<div class="clear"></div>
</div>
两种方式都会得到如下图效果:
对于第一种都浮起来,可能比较好理解,毕竟大家都一样了,谁也不能搞特殊了,所以效果正常了,#left(蓝色区)和#right(红色区)没办法从#box中跑出来了。第二种清理浮动可能不大好理解。我们需要研究下clear这个属性。所以我们需要了解下清除浮动的定义:
clear 属性定义了元素的哪边上不允许出现浮动元素。在 CSS1 和 CSS2 中,这是通过自动为清除元素(即设置了 clear 属性的元素)增加上外边距实现的。在 CSS2.1 中,会在元素上外边距之上增加清除空间,而外边距本身并不改变。
根据以上定义我们可以这样理解:#left(蓝色区)和#right(红色区)进行浮动后,脱离了#box(灰线区)的控制,#box(灰线区)相当于里面没有内容,根据默认块级元素表现,#box(灰线区)是一个宽度100%,高度为0的div,而使用clear的div没有浮动,并且使用了clear属性,那么根据清除浮动的定义,这个div会在它的上方空出来足够容纳#left和#right的空白,所以#box(灰线区)就被撑开了,虽然#left(蓝色区)和#right(红色区)还是不受它的控制,但是看起来是被它控制着,而使用clear的空div本身没有设置宽度和高度,根据默认块级元素表现,它也是个宽度100%,高度为0的元素,也即是说,它是不显示的。
接下来说一些要注意的地方和技巧
1. 右边浮动与左浮动顺序相反
左浮动:
css:
#box {
width: 500px;
border: 1px solid #d9d9d9;
}
#left {
float: left;
width: 200px;
height: 150px;
background: #54c9e8;
}
#right {
float: left;
width: 250px;
height: 150px;
background: #e678cc;
}
.clear {
clear: both;
}
html:
<div id="box">
<div id="left"></div>
<div id="right"></div>
<div class="clear"></div>
</div>
效果如图:
右浮动:
css:
#box {
width: 500px;
border: 1px solid #d9d9d9;
}
#left {
float: right;
width: 200px;
height: 150px;
background: #54c9e8;
}
#right {
float: right;
width: 250px;
height: 150px;
background: #e678cc;
}
.clear {
clear: both;
}
html:
<div id="box">
<div id="left"></div>
<div id="right"></div>
<div class="clear"></div>
</div>
效果如图:
发现有什么不同了么?html顺序一样甚至css顺序也一样,但是两个色块位置完全相反。我们回顾一下浮动的定义就明白了:直到它的外边缘碰到包含框或另一个浮动框的边框为止。按照html中得顺序,#left(蓝色区)在前面,#right(红色区)在后面,所以,都向左浮动时,#left(蓝色区)先向左浮动,#right(红色区)再向左浮动,当碰到#left(蓝色区)时停止,都向右浮动时,还是#left(蓝色区)先向右浮动,然后#right(红色区)再向右浮动,同样碰到#left(蓝色区)停止,所以就产生了以上两种效果。
2. 浮动元素的宽度
2.1 浮动元素相加实际宽度大于父元素宽度导致换行
css:
#box {
width: 600px;
overflow: hidden;
border: 1px solid #d9d9d9;
}
.box_i {
width: 200px;
height: 100px;
float: left;
margin: 10px;
background: #54c9e8;
}
html:
<div id="box">
<div class="box_i"></div>
<div class="box_i"></div>
<div class="box_i"></div>
</div>
效果如图:
也许有人会问#box(灰线区)宽600px,每个.box_i(蓝色区)宽都是200px,按说刚好,应该在一行,怎么第三个下来了呢?有这疑问的同学往上看盒模型部分,元素实际占据的宽高是要加上margin值的,所以上面.box_i(蓝色区)的width应该是180px(200-10*2)。
2.2 浮动元素被卡住
css:
#box {
width: 600px;
overflow: hidden;
border: 1px solid #d9d9d9;
}
#box1 {
width: 300px;
height: 150px;
float: left;
background: #e678cc;
}
#box2 {
width: 300px;
height: 100px;
float: left;
background: #54c9e8;
}
#box3 {
width: 300px;
height: 100px;
float: left;
background: #8add66;
}
html:
<div id="box">
<div id="box1"></div>
<div id="box2"></div>
<div id="box3"></div>
</div>
效果如图:
是不是感觉很奇怪?按照浮动原理,#box1(红色区)和#box2(蓝色区)把#box(灰线区)占满了,剩余的空间不足以放下#box3(绿色区),所以#box3(绿色区)应该浮动到最左边,在#box1(红色区)下面,但是怎么会在这个位置卡住呢?
事实是#box3(绿色区)确实被#box1(红色区)卡住了,我们再次复习下浮动的定义:浮动的框可以向左或向右移动,直到它的外边缘碰到包含框或另一个浮动框的边框为止。
好了,根据定义重新分析一遍。#box1(红色区)和#box2(蓝色区)浮动把#box(灰线区)占满了,剩余的空间不足以放下#box3(绿色区),#box3(绿色区)也浮动,只能换行,由于#box1(红色区)比#box2(蓝色区)高出一部分,#box3(绿色区)在换行浮动的时候和#box2(蓝色区)一样碰到了#box1(红色区),既然碰到了另一个浮动框的边框,那就停在这吧,所以就成上图这样了。
那么,如果我们想让#box3(绿色区)放在#box1(红色区)底下怎么办?当然是清除浮动了:
css:
#box3 {
width: 300px;
height: 100px;
clear: both;
background: #8add66;
}
然后就得到我们想要的结果了,效果如下图:
有心的同学可能已经发现,之前两个例子好像没看到clear,但是#box(灰线区)却不受浮动影响,为什么呢?哈哈,秘密在于 overflow: hidden;文章末尾会专门讲解浮动的清理。
3. 关于图文混排
通用html:
<div id="box">
<img src="http://www.mamicode.com/aa.jpg" >
<p>11月4日,受强冷空气影响,我国北方大部分地区出现大范围降温雨雪天气,其中华北、东北、内蒙古及山东半岛等地出现中到大雪。11月3日晚至4日夜,京城遭受此次寒潮过程最严重的影响,雨雪、雷电、降温和大风同时影响北京各地。市气象台根据降雨量和降雪量的总体统计,昨日全市降水量至中午便超过历史极值。而延庆降雪量则为52年来最大暴雪。</p>
</div>
3.1 默认
示例:
css:
#box {
font: 12px/18px Arial;
color: #4d4d4d;
width: 500px;
}
效果如图:
3.2 图片文字同时浮动
css:
#box {
font: 12px/18px Arial;
color: #4d4d4d;
width: 500px;
}
#box img {
float: left;
padding-right: 10px;
}
#box p {
float: left;
width: 350px;
margin: 0;
}
效果如图:
3.3 图片浮动,文字不浮动,实现文字环绕图片
css:
#box {
font: 12px/18px Arial;
color: #4d4d4d;
width: 500px;
}
#box img {
float: left;
padding-right: 10px;
}
效果如图:
关于清除浮动
前面我们已经讲了什么是清除浮动,以及为什么要清除浮动。现在讲下浮动的清理方法。
清理浮动的常用方法的有3种外加1种ie专属。
1. 父元素overflow: hidden;
我们前面用过了,这种清除浮动的使用方法是:子元素进行了浮动,给父元素添加overflow: hidden;即可清除子元素浮动对父元素的影响。比如一个ul列表,当li进行浮动后,ul没有浮动,自然受到li浮动的影响,没有高度,这时给ul增加添加overflow: hidden;即可清除li浮动对ul的影响。
原理:overflow属性会产生包裹效果,这就势必需要获得子元素的宽和高,所以变相达到了清理浮动的效果。
限制:使用这种清理方式的父元素不能或者尽量不要设置高度,比如li浮动,ul添加overflow: hidden;不要设置高度height属性。
支持:所有浏览器
2. 空元素clear
这种我们前面也用过。需要我们建立一个class: .clear { clear: both; }。
使用方法:在需要清理的浮动元素后面增加一个空标签,比如div,并使用.clear。
弊端: 对于需要大量清理浮动的页面,会产生大量额外标签。
支持:所有浏览器
3. :after伪类清理
:afer属性是css3中新加的属性,意思是在元素内容末尾添加内容。:after中的content属性可以设置追加内容。这用清除方式原理同空元素clear,区别是不用使用无意义的空标签了。
.clearfix:after {
content: "";
display: block;
height: 0;
clear: both;
}
使用方法:同overflow清除浮动方法,子元素浮动对父元素造成影响,可以给父元素使用.clearfix。
原理: 在元素内容末尾追加空内容,并设置为块级属性,高度为0,即不可见,然后清除掉之前元素的浮动。例如,ul列表中的li进行浮动,ul使用了clearfix后,:after标签就像a:hover一样,会有一个行为,这个行为就是在ul的内容最末尾,也就是最后一个li的后面增加一个空内容(content: ""),并将其设置为块,高度设为0不可见,并设置clear: both; 将浮动的li清理掉。
支持:所有支持:after属性的浏览器
4. ie专属zoom
zoom: 1;
zoom是ie系列专属属性,用来进行放大,zoom: 1;的意思的放大1倍,也就是原大小。在ie系列中,使用zoom的元素会自动获得layout,达到清除浮动的效果,当然主要是针对以前的版本IE6和IE7有效,因为IE8之后改动较大,zoom不再能触发layout属性所以无法达到清除浮动的效果,但是我在网上查阅了一些资料,发现IE8分为IE8(Q)和IE8(S)(我不知道这是什么意思,知道的请告诉我,呵呵),IE8(Q)不支持:after属性,但是zoom可以触发layout,IE8(S)支持:after但是zoom不能触发layout。可以参考一下两篇文章:
RM3007: 在 IE6 IE7 IE8(Q) 中包含被清除浮动的浮动元素的块级元素的背景在某些情况下不是设置值
RS8010: IE6 IE7 IE8(Q) 不支持 ‘:before‘ 和 ‘:after‘ 伪元素
根据以上特性,我们可以写出一个通用型的清理浮动:万能清理浮动写法
关于浮动和清除浮动