清楚浮动边界塌陷bfc

32次阅读

共计 4011 个字符,预计需要花费 11 分钟才能阅读完成。

CSS 清浮动处理(Clear 与 BFC)
在 CSS 布局中 float 属性经常会被用到,但使用 float 属性后会使其在普通流中脱离父容器,让人很苦恼

1 浮动带来布局的便利,却也带来了新问题

复制代码
1 <!doctype html>
2 <html lang=”en”>
3 <head>
4 <meta charset=”UTF-8″>
5 <title>Clear float</title>
6 <style type=”text/css”>
7 .container{
8 margin: 30px auto;
9 width:600px;
10 height: 300px;
11 }
12 .p{
13 border:solid 3px #a33;
14 }
15 .c{
16 width: 100px;
17 height: 100px;
18 background-color: #060;
19 margin: 10px;
20 float: left;
21 }
22 </style>
23 </head>
24 <body>
25 <div class=”container”>
26 <div class=”p”>
27 <div class=”c”></div>
28 <div class=”c”></div>
29 <div class=”c”></div>
30 </div>
31 </div>
32 </body>
33 </html>
复制代码
我们希望看到的效果是这样的

但结果却是这样的

父容器并没有把浮动的子元素包围起来,俗称塌陷,为了消除这种现象,我们需要一些清除浮动的技巧。

2 如何清理浮动

清理浮动一般有两种思路

利用 clear 属性,清除浮动
使父容器形成 BFC
分别看一下

2.1 利用 clear 属性,清除浮动

clear 属性是个什么东东呢?clear 属性规定元素的哪一侧不允许其它之前浮动元素,修改一下刚才代码

复制代码
<div class=”p”>

<div class="c"></div>
<div class="c" style="clear:left;"></div>
<div class="c"></div>

</div>
复制代码

第二个 div 添加了 clear:both 属性后,其左侧的 div(第一个 div)不再浮动,所以后面的 div 都还行 (huan hang) 了。我们可以利用这点儿在父容器的最后添加一个空的 div,设置属性 clear:left,这样就可以达到我们目的了。

2.1.1 添加空 div 清理浮动

对我们刚才代码稍作修改

复制代码
<div class=”p”>

<div class="c"></div>
<div class="c"></div>
<div class="c"></div>
<div style="clear:left;"></div>

</div>
复制代码
也就是在父容器最后添加

<div style=”clear:left;”></div>
看看效果

果真好使了,有些同学看了后可能感觉奇怪,为什么想上一个例子修改第二个 div

<div class=”c” style=”clear:left;”></div>
没有变成这样的效果

说一下自己的拙见,clear:left 属性只是消除其左侧 div 浮动对它自己造成的影响,而不会改变左侧 div 甚至于父容器的表现,在父容器看来,三个 div 还都是 float 的,所以高度依旧塌陷。但是我们在最后添加了一个非浮动的 div,由于它有 clear:left 属性,所以它会按照左侧 div 不浮动来定位自己,也就是定位到下一行,而父容器看到有一个非浮动、普通流的子元素元素,会将其包围,这样造成了顺便也把三个浮动元素也包裹起来的效果,高度不再塌陷(不知道说明白没有或者这种理解对不对,还望明白的同学指点)。

当然除了添加 div,还可以添加 br 等其它 html 元素,原理相同,不再赘述。

2.1.2 使用 CSS 插入元素

上面的做法浏览器兼容性不错,但是有个很大的问题就是向页面添加了内容来达到改变效果的目的,也就是数据和表现混淆,既然是变现,看看怎么使用 CSS 来解决这一问题。根本的做法还是向父容器最后追加元素,但我们可以利用 CSS 的:after 伪元素来做此事。

添加一个类 floatfix

复制代码
.floatfix:after{

content:"."; 
display:block; 
height:0; 
visibility:hidden; 
clear:left;

}
复制代码
对父容器添加此类

<div class=”p floatfix”>

<div class="c">1</div>
<div class="c">2</div>
<div class="c">3</div>

</div>
这样我们就可以看到正确效果了

简单解释一下,对父容器添加 floatfix 类后,会为其追加一个不可见的块元素,然后设置其 clear 属性为 left,和刚才原理类似。

2.1.3 大师手笔

Nicolas Gallagher 在 A new micro clearfix hack 中提供了一种看起来更清爽的做法

.floatfix:after{

content:"";
display:table;
clear:both;

}
Nicolas Gallagher 原文中还有:before 是为了处理 margin 边距重叠,本文中没有列出来。

有同学会提出来了上面方法看起来不错,但是 IE6、7 不支持伪元素怎们办?这就需要我们使用 BFC/haslayout 的姿势了

2.2 使父容器形成 BFC

经过了前些日子园里关于 BFC 的狂轰滥炸相信大家都对 BFC 有了一定的了解,不过瘾的同学可以看看 Block Format Content,BFC 有三个特性

BFC 会阻止垂直外边距(margin-top、margin-bottom)折叠
按照 BFC 的定义,只有同属于一个 BFC 时,两个元素才有可能发生垂直 Margin 的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡 (例如边框,非空内容,padding 等) 就会发生 margin 重叠。

因此要解决 margin 重叠问题,只要让它们不在同一个 BFC 就行了,但是对于两个相邻元素来说,意义不大,没有必要给它们加个外壳,但是对于嵌套元素来说就很有必要了,只要把父元素设为 BFC 就可以了。这样子元素的 margin 就不会和父元素的 margin 发生重叠了。

BFC 不会重叠浮动元素
BFC 可以包含浮动
我们可以利用 BFC 的第三条特性来“清浮动”,这里其实说清浮动已经不再合适,应该说包含浮动。也就是说只要父容器形成 BFC 就可以,简单看看如何形成 BFC

float 为 left|right
overflow 为 hidden|auto|scroll
display 为 table-cell|table-caption|inline-block
position 为 absolute|fixed
我们可以对父容器添加这些属性来形成 BFC 达到“清浮动”效果

2.2.1 利用 float 来使父容器形成 BFC

简单修改一下代码

<div class=”p” style=”float:left;”>

<div class="c">1</div>
<div class="c">2</div>
<div class="c">3</div>

</div>
这样我们可以得到结果

我们可以看到父容器高度没有塌陷,但是长度变短了,因为 div 应用 float‘后会根据内容来改变长度,这个在很多时候很有用,但是我们不希望有这种效果怎么办?

2.2.2 使用 BFC 的其它局限

上面提到使用 BFC 使用 float 的时候会使父容器长度缩短,而且还有个重要缺陷——父容器 float 解决了其塌陷问题,那么父容器的父容器怎么办?难道要全部使用 folat 吗(确实有这种布局方式倒是)。BFC 的几种方式都有各自的问题,overflow 属性会影响滚动条和绝对定位的元素;position 会改变元素的定位方式,这是我们不希望的,display 这几种方式依然没有解决低版本 IE 问题。。。

看起来还是第一种方式比较好,可是低版本 IE 该怎么办呢?

2.2.3 hasLayout

我们知道在 IE6、7 内有个 hasLayout 的概念,很多 bug 正式由 hasLayout 导致的,当元素的 hasLayout 属性值为 false 的时候,元素的尺寸和位置由最近拥有布局的祖先元素控制。当元素的 hasLayout 属性值为 true 的时候会达到和 BFC 类似的效果,元素负责本身及其子元素的尺寸设置和定位。我们可以利用这点儿在 IE6、7 下完成清浮动,先看看怎么使元素 hasLayout 为 true

position: absolute
float: left|right
display: inline-block
width: 除“auto”外的任意值
height: 除“auto”外的任意值
zoom: 除“normal”外的任意值
writing-mode: tb-rl
在 IE7 中使用 overflow: hidden|scroll|auto 也可以使 hasLayout 为 true

3 一个相对靠谱的解决方案

经过上面的比较我们可以得出一个相对靠谱的解决方案

在 IE+、现代浏览器上使用伪元素
在 IE6、7 使用 hasLayout
具体应该使用哪种方式来使元素 hasLayout 为 true 呢?相对而言 zoom:1 比较好,因为不会造成其它影响。想造成只在 IE6、7 上使用某些 CSS 的效果,我们还得需要一些 CSS hack 的知识,感兴趣同学可以看看 CSS hack,我们可以写出这样的 CSS

复制代码
.floatfix{

*zoom:1;

}
.floatfix:after{

content:"";
display:table;
clear:both;

}
复制代码
4 最后

虽然我们得出了一种浏览器兼容的靠谱解决方案,但这并不代表我们一定得用这种方式,很多时候我们的父容器本身需要 position:absolute 等形成了 BFC 的时候我们可以直接利用这些属性了,大家要掌握原理,活学活用。总而言之清理浮动两种方式

利用 clear 属性,清除浮动
使父容器形成 BFC

正文完
 0