揭秘CSS(第 1 版)
5.3.2 清理
阅读(

概述

CSS选择器

字体和文本

盒模型

元素的定位

普通流

定位

浮动

浮动

清理

虽然浮动可以便于页面布局,但同时会产生一些问题,也就是常说的副作用。浮动元素最常见的缺陷是:父元素的高度塌陷和影响兄弟元素的位置。

首先,看看父元素的高度塌陷。假设有一个容器,其中两个子元素,一个子元素向左浮动,一个子元素向右浮动。代码如下:

.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 就相当于一个空标签,其高度就会塌陷为零,使得浮动元素溢出到容器外面。如图 5‑29 所示:

浮动导致容器高度塌陷
图5-29 浮动导致容器高度塌陷

这种塌陷会影响、甚至破坏布局,如果父元素没有边框,也不包含任何可见背景,这个问题就很难被注意到,但它却是一个很重要的问题。

再来看看浮动元素如何影响兄弟元素的位置。当容器的高度为 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>

上述的布局为两栏布局,主栏向左浮动,侧栏向右浮动,并且侧栏的高度小于主栏的高度。页脚便会上跳到侧栏的剩余空间。如图 5‑30 所示:

浮动使相邻元素上跳
图5-30 浮动使相邻元素上跳

很显然,无论是高度塌陷,还是影响兄弟元素的位置,都不是使用浮动的目的。浮动只是为了改变元素的布局,却造成了不必要的影响。因此,需要清除浮动带来的影响。

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 。

关于作者

歪脖先生,十五年以上软件开发经验,酷爱Web开发,精通 HTML、CSS、JavaScript、jQuery、JSON、Python、Less、Bootstrap等,著有《HTML宝典》、《揭秘CSS》、《Less简明教程》、《JSON教程》、《Bootstrap2用户指南》、《Bootstrap3实用教程》,并全部在 GitHub 上开源。

如果本教程对您帮助很大,请随意打赏。您的支持,将鼓励我写出更好的教程!

← 键盘方向键翻页 →
返回顶部 手机访问 关注微信 返回底部

扫码访问歪脖网

随时随地,想看就看

关注歪脖网微信

分享 web 知识、交流 web 经验