w3ctech

CSS FLOAT 学习笔记

FLOAT

@Keywords: Float Clearfix ::after BFC hasLayout

@Author: GreenMelon @吾南蛮野人 陈灿坚

@分享地址:http://pan.baidu.com/s/1eQqagt8

@Date: 二O一五.十月.24th

[TOC]

CSS的定位机制

  • 常规流(Normal-Flow)
  • 浮动(Float)
  • 绝对定位(Absoluted Position)

浮动的特性

  • 浮动框可以左右浮动,直至它的外边缘遇到包含框或者另一个浮动框的边缘
  • 浮动框脱离了文档的常规流。文档的常规流就会忽略浮动框的存在
  • 浮动框不会影响到块级框的布局,但会影响内联框的排列
  • 当浮动框高度超出包含框的时候,包含框不会自动伸缩来闭合浮动框。如果包含框内部不存在其他普通流元素,其高度为0。即所谓的高度塌陷现象

浮动的分类

  • 清除浮动: Clearing-Float,浮动元素的左右两边是否允许其他元素的存在
  • 闭合浮动: Enclosing-Float,浮动元素重新被包含进父元素(闭合浮动的目的在于使包含框表现出正常的高度)

清除(闭合)浮动的方法

1 clear清除法

1.1 添加空元素

我们先来看一个典型的浮动的例子

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
</div>
<div class="wrapper-siblings">wrapper-siblings</div>
body {
  font-size: 32px;
  text-align: center;
  color: #fff;
}
.wrapper {
  background-color: green;
}
  .float-left,
  .float-right {
    width: 40%;
    height: 100px;
    line-height: 100px;
    background-color: orange;
  }
  .float-left {
    float: left;
  }
  .float-right {
    float: right;
  }

.wrapper-siblings {
  height: 100px;
  line-height: 100px;
  background-color: crimson;
}

由于 .wrapper 的两个子元素 .float-left 和 .float-right 浮动,造成 .wrapper 的高度坍塌现象:

点击 demo 查看

我们可以在浮动元素末尾添加一个空元素来清除浮动:

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
  <!-- 添加空元素 -->
  <div class="clear"></div>
</div>
<div class="wrapper-siblings">wrapper-siblings</div>
  /* For modern browsers */
  .clear {
    clear: both;  /* 清除左右浮动 */
  }

  /* For IE browsers */
  .clear {
    clear: both;
    height: 0;
    line-height: 0;
    font-size: 0;
  }

效果图:

点击 demo 查看

优点:简单易用

缺点:增加了无意义的空标签,有违语义化,有违结构与表现相分离,不利于后期维护

1.2 使用br元素

我们也可以使用 br 元素,利用 br 元素的 clear = all | left | right | none 属性

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
  <!-- 使用br元素 -->
  <br clear="all">
</div>
<div class="wrapper-siblings">wrapper-siblings</div>
body {
  font-size: 32px;
  text-align: center;
  color: #fff;
}
.wrapper {
  background-color: green;
}
  .float-left,
  .float-right {
    width: 40%;
    height: 100px;
    line-height: 100px;
    background-color: orange;
  }
  .float-left {
    float: left;
  }
  .float-right {
    float: right;
  }

.wrapper-siblings {
  height: 100px;
  line-height: 100px;
  background-color: crimson;
}

效果图:

点击 demo 查看

如果在父元素外部使用 br 元素:

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
</div>
<!-- 在外部使用br元素 -->
<br clear="all">
<div class="wrapper-siblings">wrapper-siblings</div>

高度坍塌现象仍然存在:

点击 demo 查看

优点:比空元素方式语义稍强

缺点:同样增加了无意义的空元素,不利于后期维护

1.3 使用伪元素::after

NOTE: 由于 IE6-7 不支持 ::after,使用 zoom: 1; 触发 hasLayout

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
</div>
<div class="wrapper-siblings">wrapper-siblings</div>
body {
  font-size: 32px;
  text-align: center;
  color: #fff;
}
.wrapper {
  margin-bottom: 10px auto;
  background-color: green;
}
.wrapper::after {
  content: "";  /* 空内容的默认高度为0,避免生成的内容破坏原有布局的高度 */
  display: block;  /* 使生成的内容以块级元素显示,占满剩余空间 */
  height: 0;  /* 当内容不为空时,设置0高度,避免生成的内容破坏原有布局的高度 */
  visibility: hidden;  /* 使生成的内容不可见,避免影响被其盖住的内容的交互事件 */
  clear: both;  /* 关键:清除左右浮动 */
}
  .float-left,
  .float-right {
    width: 40%;
    height: 100px;
    line-height: 100px;
    background-color: orange;
  }
  .float-left {
    float: left;
  }
  .float-right {
    float: right;
  }

.wrapper-siblings {
  height: 100px;
  line-height: 100px;
  background-color: crimson;
}

效果图:

点击 demo 查看

优点:结构和语义化都正确

缺点:复用方式不当会造成代码量增加

2 触发BFC

2.1 父元素 overflow: hidden | auto;

通过设置父元素 overflow 的值为 visible 以外的值,从而触发 BFC;在 IE6 中还需要触发 hasLayout,例如 zoom: 1;

<div class="wrapper">
  <div class="float-left">float-left</div>
  <div class="float-right">float-right</div>
</div>
<div class="wrapper-siblings">wrapper-siblings</div>
body {
  font-size: 32px;
  text-align: center;
  color: #fff;
}
.wrapper {
  overflow: hidden;  /* 触发BFC */
  background-color: green;
}
  .float-left,
  .float-right {
    width: 40%;
    height: 100px;
    line-height: 100px;
    background-color: orange;
  }
  .float-left {
    float: left;
  }
  .float-right {
    float: right;
  }

.wrapper-siblings {
  height: 100px;
  line-height: 100px;
  background-color: crimson;
}

效果图:

点击 demo 查看

优点:不存在结构和语义化问题

缺点:内容过多时,不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素

2.2 其他方式

我们也可以使用其他方式触发BFC,效果和使用 overflow 类似。在后面的关于 BFC 的介绍中,我们再详细阐述。

3 小结

通过对比,我们不难发现,其实清除(闭合)浮动的方法无非有两类:

  1. 清除浮动:通过在浮动元素的末尾添加一个空元素,设置 clear:both 属性来清除浮动。after 伪元素其实也是通过在元素的后面生成了一个空白内容的块级元素

  2. 闭合浮动:通过设置父元素的 overflow 等属性触发 BFC 来闭合浮动

BFC

BFC: Block Formatting Contexts (块级格式化上下文,CSS3 改称为 Flow Root)

BFC 是 Web 页面中盒模型布局的 CSS 渲染模式。它的定位体系属于常规文档流。通俗地讲:创建了 BFC 的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素,同时 BFC 仍然属于文档中的常规流。

BFC的触发条件

  • position: absolute | fixed;
  • display: table-caption | table-cell | inline-block | inline-flex | flex;
  • float: left | right;
  • visibility: hidden | scroll | auto;

BFC的特性

BFC的用途

1 父元素的高度值

默认的 web 布局

<div class="container">
  <p class="para">Sibling 1</p>
  <p class="para">Sibling 2</p>
</div>
body {
  font-size: 24px;
  text-align: center;
  color: #fff;
}
.container {
  margin: 0;
  background-color: crimson; 
}
  .para {
    height: 50px;
    line-height: 50px;
    background-color: orange;
  }

效果图:

Alt text

若子元素有外边距,父元素无外边距,则会发生子元素外边距越界现象

  .para {
    margin: 30px 0;
  }

效果图:

Alt text

若父元素触发了BFC,则会生成一个独立的盒子包含子元素,包括子元素的外边距

.container {
  overflow: hidden;  /* 触发BFC */
}

效果图:

Alt text

2 防止外边距重叠

在上面,我们已经看到了子元素的外边距重叠现象。如何防止呢?我们必须牢记在心的是:毗邻的块盒的垂直外边距重叠只有当它们是在同一BFC时才会发生。如果它们属于不同的BFC,那么外边距将不会重叠。所以通过创建一个新的 BFC 我们可以防止外边距重叠。

<div class="container">
  <p class="para">Sibling 1</p>
  <p class="para">Sibling 2</p>
  <!-- 创建新的BFC -->
  <div class="new-bfc">
    <p class="para">Sibling 3</p>
  </div>
</div>
body {
  font-size: 24px;
  text-align: center;
  color: #fff;
}
.container {
  margin: 0;
  overflow: hidden;  /* 创建BFC */
  background-color: crimson; 
}
  .para {
    height: 50px;
    line-height: 50px;
    margin: 30px 0;
    background-color: orange;
  }
  .new-bfc {
    overflow: hidden;  /* 创建新的BFC */
  }

效果图:

Alt text

3 闭合浮动

一个 BFC 可以包含浮动元素。很多时候我们会碰到这种情况:一个容器里的浮动元素脱离页面的常规流,导致容器的高度坍塌。我们通常使用伪元素来清除浮动。但我们同样可以通过定义一个 BFC 来达到这个目的。

<div class="wrapper">
  <div class="floated">floated</div>
  <div class="floated">floated</div>
  <div class="floated">floated</div>
  <div class="floated">floated</div>
  <div class="floated">floated</div>
</div>
.wrapper {
  border: 5px solid green;
  background-color: crimson;
}
.floated {
  float: left;
  width: 15%;
  height: 100px;
  border-radius: 5px;
  margin: 0 30px;
  text-align: center;
  line-height: 100px;
  background-color: orange;
}

效果:

Alt text

为了解决这个问题,我们通过在容器中创建一个 BFC 包含浮动元素

.wrapper {
  overflow: hidden;  /* 创建BFC */
  padding: 30px;
}

效果图:

Alt text

现在,这个容器的高度将扩展到可以包含它的浮动的子元素。在这个 BFC 中,这些元素将会回到页面的常规文档流

4 防止文字环绕

有时候一个浮动 div 周围的文字环绕着它(如 Figure1 所示)。但是在某些场景中我们想要的效果如 Figure2 所示。为了解决这个问题,我们可能使用外边距,但是我们也可以使用一个 BFC 来解决。

Alt text

首先让我们理解文字环绕现象的产生原因:

Alt text

上图的 HTML Markup 如下所示:

<div class="container">
  <div class="floated">Floated div</div>
  <p>Quae hic ut ab perferendis sit quod architecto,dolor debitis quam rem provident aspernatur tempora expedita.</p>
</div>

在上图中的整个黑色区域为 p 元素。正如我们所看到的,由于这个 .floated 浮动了,脱离了常规文档流,不占空间。因此 p 元素自动上移,占据 .floated 原有的空间。因此 p 元素出现在 .floated 的下方。浮动框不会影响块级框的布局,但是会影响内联框的排列。因此 p 元素的 line boxes(文本行) 水平收缩进行了移位,为浮动元素提供了空间。随着文字的增加,因为 line boxes 不再需要移位,最终将会环绕在浮动元素的下方。

让我们回顾W3C 的标准:

在 BFC 中,每个盒子的左外边框紧挨着包含块的左边框(从右到左的场景中,则为右边框紧挨着包含块的右边框),即使在浮动里也是这样的(尽管一个盒子的边框会因为浮动而萎缩)。除非这个盒子的内部创建了一个新的BFC(这种情况下,由于浮动,盒子本身将会变得更窄)

根据标准,如果这个 p 元素创建了一个新的 BFC,那么它将不会紧挨着容器块的左边缘。这样就解决了文字环绕在浮动元素周围的问题。

让我们从文字环绕的布局开始:

<div class="container">
  <div class="floated">Floated</div>
  <p class="para">Quae hic ut ab perferendis sit quod architecto,dolor debitis quam rem provident aspernatur tempora expedita.</p>
</div>
.container {
  width: 300px;
  padding: 20px;
  border-radius: 5px;
  font-size: 24px;
  background-color: crimson;
}
  .floated {
    float: left;
    width: 40%;
    height: 150px;
    border-radius: 5px;
    text-align: center;
    line-height: 150px;
    background-color: orange;
  }
  .para {
    padding-left: 10px;
    margin: 0;
    color: #fff;
  }

效果图:

Alt text

让我们创建 BFC 解决文字环绕现象:

.container {
  width: 300px;
  padding: 20px;
  border-radius: 5px;
  font-size: 24px;
  text-align: center;
  background-color: crimson;
}
  .floated {
    float: left;
    width: 40%;
    height: 150px;
    border-radius: 5px;
    line-height: 150px;
    background-color: orange;
  }
  .para {
    overflow: hidden;  /* 创建BFC */
    padding-left: 10px;
    margin: 0;
    color: #fff;
  }

效果图:

Alt text

IE6-7的 hasLayout

IE 的 hasLayout 与 BFC 类似。IE6-7 的显示引擎使用一个称为布局(layout)的内部概念来控制元素的尺寸和定位。那些 hasLayout 的元素负责本身及其子元素的尺寸设置和定位。如果一个元素的 hasLayout 为 false,那么它的尺寸和定位由最近的拥有布局的祖先元素控制。

hasLayout的触发条件

  • position: absolute;
  • display: inline-block;
  • float: left | right;
  • width: 非auto
  • height: 非auto
  • zoom: 非normal
  • writing-mode: tb-rl;
  • overflow: hidden | scroll | auto; (IE7特有)

IE8 使用了全新的显示引擎,据称不使用 hasLayout 属性了,因此解决了很多深恶痛绝的 bug。但 IE8-11 通过「document.documentElement.currentStyle.hasLayout」依然可以获得 hasLayout 的标志。

小结

综上所述,在支持 BFC 的浏览器(IE8+,firefox,chrome,safari)通过创建新的 BFC 闭合浮动;在不支持 BFC 的浏览器(IE6-7)通过触发 hasLayout 闭合浮动。

清除(闭合)浮动的优化方法

  • 优化1
    /* For IE 6/7 only */
    .clearfix {
    *zoom: 1;
    }
    /* For modern browsers */
    .clearfix::after {
    content: "200B";  /* 零宽度空格的Unicode字符 */
    display: block;
    height: 0;
    clear: both;
    }
    
  • 优化2
    /* For IE 6/7 only */
    .clearfix {
    *zoom: 1;
    }
    /* For modern browsers */
    .clearfix::before,  /* before用于处理垂直边距叠加,视情况而定可不加 */
    .clearfix::after {
    content: "";
    display: table;
    }
    .clearfix:after {
    clear: both;
    overflow: hidden;
    }
    
    reference: A new micro clearfix hack

REFERENCE:

w3ctech微信

扫码关注w3ctech微信公众号

共收到4条回复