虽然浮动可以便于页面布局,但同时会产生一些问题,也就是常说的副作用。浮动元素最常见的缺陷是:父元素的高度塌陷和影响兄弟元素的位置。
首先
看看父元素的高度塌陷。假设有一个容器,其中两个子元素,一个子元素向左浮动,一个子元素向右浮动。代码如下:
.wrapper {
border: 2px dashed #ccc;
}
.wrapper > div {
width: 80px;
height: 60px;
border: 1px dashed #444;
}
.floatL {
float: left;
}
.floatR {
float: right;
}
<div class = "wrapper">
<div class = "floatL">box1 </div>
<div class = "floatR">box2 </div>
</div>
上述容器 wrapper 的高度为auto,且只包含浮动元素。由于浮动元素脱离了文档流,因此,容器 wrapper 就相当于一个空标签,其高度就会塌陷为零,使得浮动元素溢出到容器外面。
这种塌陷会影响、甚至破坏布局,如果父元素没有边框,也不包含任何可见背景,这个问题就很难被注意到,但它却是一个很重要的问题。
再来看看浮动元素如何影响兄弟元素的位置。当容器的高度为 auto,且只包含浮动元素时,如果浮动元素的高度不相同,而剩余空间足够容纳后面的元素时,后面的元素就会上跳到剩余的空间。代码如下:
.wrapper {
border: 2px dashed #ccc;
}
main {
float: left;
}
aside {
float: right;
}
footer {
float: left;
}
<div class = "wraper">
<main>main</main>
<aside>aside</aside>
<footer>footer</footer>
</div>
上述的布局为两栏布局,主栏向左浮动,侧栏向右浮动,并且侧栏的高度小于主栏的高度。页脚便会上跳到侧栏的剩余空间。
很显然,无论是高度塌陷,还是影响兄弟元素的位置,都不是使用浮动的目的。浮动只是为了改变元素的布局,却造成了不必要的影响。因此,需要清除浮动带来的影响。
CSS中,把清除浮动影响所进行的处理,叫做清理浮动(或清除浮动)。一般有两种处理思路:使用 clear属性和让容器创建一个BFC。
每种思路中都包含多种方法,但并不是每一种方法都尽善尽美,接下来简单介绍这些方法的原理及适用场合,可以根据实际情况,选择合适的方法。
使用 clear属性
CSS中的 clear属性,用来规定在元素的哪一侧不允许出现浮动元素,可选值有 none | left | right | both,默认值为 none,表示不清除,左右两侧均允许出现浮动元素。left 表示清除左侧,在左侧不允许出现浮动元素;right 表示清除右侧,在右侧不允许出现浮动元素;both 表示清除两侧,左右两侧均不允许出现浮动元素。
1)使用带clear属性的空元素
这也是W3C推荐使用的方法,首先在CSS中定义一个清理的 class,然后在浮动元素的后面,使用一个空元素 <div class = "clear"></div> 或 <br class = "clear" />
。如:
.clear {
clear: both;
}
<div class = "wraper">
<div class = "floatL">box1 </div>
<div class = "floatR">box2 </div>
<br class = "clear" />
</div>
这种方法的优点是简单、代码少、浏览器兼容性好。但是,需要添加无语义的html元素,违背了表现和内容相分离的原则,代码不够优雅,增加了后期维护的难度。
2)借用邻接元素处理
什么都不做,给浮动元素后面的那个元素添加 clear属性。假如在浮动元素后面有一个 p 元素,可以为 p 元素添加 clear属性,来间接清除浮动。如:
<div class = "wraper">
<div class = "floatL">box1 </div>
<div class = "floatR">box2 </div>
<p class = "clear"></p>
</div>
如果你很明确的知道接下来的元素是什么,这个方法很不错,它不需要 hack,不添加额外的元素。但是,使用这种方法,必须确保浮动元素后面确实有元素。如果没有元素,巧妇难为无米之炊,也没有办法。
3)使用CSS的 :after 伪元素
结合 :after 伪元素(注意这不是伪类,而是伪元素,代表一个元素之后最近的元素)和触发布局的 IE hack,可以完美兼容当前各大主流浏览器。
给包含浮动元素的容器添加一个 clearfix 的 class,然后给这个 class 添加一个 :after 伪元素,在元素末尾添加一个看不见的块元素,让这个块元素来清除浮动。
.clearfix:after {
content: ".";
clear: both;
display: block;
height: 0;
visibility: hidden;
}
<div class = "wrapper clearfix">
<div class = "floatL">box1 </div>
<div class = "floatR">box2 </div>
</div>
通过CSS伪元素,在容器的末尾,插入一个点 ".",然后通过 height 和 visbility 属性使其不可见,再为插入的点设置 clear属性来清除浮动,其原理跟上述两种方法类似。
事实上,上述方法插入任何内容,都可以清除浮动。当然,如果插入一个空格的话,就不必设置 height 和 visbility 属性,代码会跟简洁。如:
.clearfix:after {
content: "";
clear: both;
display: block;
}
需要注意的是,由于IE7及以下的版本不支持 :after 伪元素,因此还需要为 .clearfix 设置width、或 height、或 zoom 等一系列属性,来触发布局(即,使IE私有属性 hasLayout 的值为 true)。如:
.clearfix {
*zoom: 1;
}
在这些属性值中,zoom 用于设置元素的缩放比例,取值 1 就会使用元素的实际尺寸。因此,使用 zoom: 1 既可以触发布局,又不会对元素造成其他影响,相对而言比较安全。
让容器创建BFC
可以利用BFC特性,来清除浮动。准确的讲,说清除浮动不太合适,应该说是让容器创建一个BFC,来包含浮动元素。可以为容器设置以下属性,来创建一个新的BFC,间接实现清除浮动的效果:
float: left | right
position: absolute | fixed
overflow: hidden | auto | scroll
display: inline-block | table-cell | table | flex | inline-flex
虽然设置上述属性都可以创建BFC,实现清除浮动的效果,但是,float、position、display 属性可能会影响整体布局。因此,最常用的还是设置 overflow 属性。
1)让容器浮动
让容器浮动后,容器就会创建一个新的BFC,使它可以包含浮动元素。计算BFC的高度时,浮动子元素也参与计算。因此,容器的高度就表现正常,其他框的位置也就正常了。
.wrapper {
float: left;
border: 2px dashed #ccc;
}
让容器浮动后,容器的高度确实没有塌陷,但是,容器的宽度可能会发生变化,因为浮动元素的宽度是有其内容决定的(显式设置 width 属性者除外),这可能会影响整体布局。
2)为容器添加 position 属性
如果为容器设置 position: absolute 或 position: fixed,容器就会创建一个新的BFC,使它可以包含浮动元素。
.wrapper {
position: absolute;
border: 2px dashed #ccc;
}
另外,由于IE7及以下的版本不支持BFC,还需要触发布局。设置 position: absolute,IE6和IE7都可以触发布局。但是,IE6不支持 position: fixed,还需要为容器设置 zoom: 1,来触发布局。
3)为容器添加 overflow 属性
如果为容器设置 overflow: hidden 或 overflow: auto,容器就会创建一个新的BFC,使它可以包含浮动元素。
.wrapper {
overflow: hidden;
border: 2px dashed #ccc;
}
另外,由于IE7及以下的版本不支持BFC,还需要触发布局。在IE7中,把 overflow属性设置为 visible 之外的值,就可以触发布局,IE6则不行。因此,在IE6中,可以为容器设置 zoom: 1,来触发布局。
这个方法不需要额外元素,有着较好的语义性,也比较简单。但是,需要要记住,overflow 属性不是为清除浮动而定义的,注意不要隐藏了不该隐藏的内容或触发了不必要的滚动条。
说明:BFC 与 hasLayout
从表现上来说,hasLayout 跟 BFC 的功能很相似,只是 hasLayout 自身存在很多问题,导致了 IE6-7 中的一系列 bug。
既然 hasLayout 有着跟 BFC 相似的功能,而 IE7 及以下的版本不支持 BFC。因此,为了避免不同浏览器下的表现差异,在实际开发中,需要创建 BFC 的元素,同时也要触发 hasLayout。
事实上,在实际开发中,很多莫名其妙的问题,都是由此产生的。当然同样地,如果一个元素没有创建 BFC,也要尽量保证它没有触发 hasLayout 。
本文共 1862 个字数,平均阅读时长 ≈ 5分钟
评论 (0)