css之BFC与float

288 阅读4分钟

BFC

BFC(Block Formatting Context)块级格式化上下文,指一个独立的渲染区域或者说是一个隔离的独立容器

形成BFC的条件

  1. 浮动元素,float 除 none 以外的值
  2. 定位元素,position(absolute,fixed)
  3. display 为以下其中之一的值 inline-block,table-cell,table-caption
  4. overflow 除了 visible 以外的值(hidden,auto,scroll)

BFC的特性

  1. bfc的区域不会与float的元素区域重叠,可以用来排版
  2. 计算bfc的高度时,浮动元素也参这与计算,就把浮动导致父级塌陷给抵消了,那么就可以清除浮动
  3. bfc就是页面上的一个独立容器,容器里面的子元素不会影响外面元素

BFC的应用场景

外边距折叠

在常规文档流中,两个兄弟盒子之间的垂直距离是由他们的外边距所决定的,但不是他们的两个外边距之和,而是以较大的为准。

那么有没有方法让垂直外边距不折叠呢?答案是:有。特性的第3条就说了:bfc就是页面上的一个独立容器,容器里面的子元素不会影响外面元素,同样外面的元素不会影响到BFC内的元素。

两栏布局

两栏布局也是因为通过overflow: hidden创建了BFC,形成了一个独立的容器,这样右边的内容不会被浮动元素所影响。

. {
    float: left; /*创建bfc */
    width: 200px;
    height: 300px;
    margin-right: 10px;
    background-color: red;
}

.right {
    overflow: hidden;/*创建bfc */
    height: 300px;
    background-color: purple;
}

float

float设计的初衷

很多新手在布局的时候,总喜欢用float来实现。例如一个三栏布局,左右固定,中间自适应,有些人会通过float来一列一列把它们砌起来。这样的布局极其容易崩溃,只要高度或者宽度稍微有些变化,整个页面都会错乱。因此float设计的初衷并不是用来布局的,其本意仅仅是实现图片文字环绕效果,即图片左浮动,文字环绕图片,如下图所示:

<div>
  <img src="./card.jpg" alt="" class="float">
  <p class="content">文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕文字环绕</p>
</div>

.float {
  width: 150px;
  float: left;
}
.content {
  width: 400px;
}

css37.jpg

float的特性

包裹性

包裹性包含了包裹和自适应两个特性

  • 包裹:指的是一个浮动元素没有设置宽度,则浮动元素的宽度就是该浮动元素的子元素的宽度
  • 自适应:如果浮动元素的父元素有设置宽度,并且浮动元素宽度超出了父元素,则浮动元素的宽度最终表现为父元素的宽度,这就是为什么float可以实现自适应布局的原因。

块状格式化上下文BFC

设定了float的元素,其display的最终值会表现为block或者table。因此,设置了float的元素,下面的写法是多余的:

.float {
  float: left:
  display: block; // 多余
}

.float {
  float: left;
  vertical-align: middle; /* 不起作用 */
}

破坏文档流

这是float最本质的特性,因此float设计的初衷就是破坏文档流。设置float的元素,会导致父元素高度塌陷,我们来看个例子:

css38.jpg

可以看到,父元素的高度为0,但这不是bug,而是float本身就是这样设计的,因此只有让父元素高度塌陷了,后面的元素才有机会浮上来。但是仅仅是这样还是不可以形成图片环绕效果的,不然文字浮上来就只会覆盖在图片上面。这里面还隐藏着一个特性:

行框盒子和浮动元素的不可重叠性:这点是与定位元素最大的不同,就是浮动元素不会和其他元素重叠,但是定位元素会发生重叠

意思是说行框盒子和浮动元素不会发生重叠,因此,下面的文字浮上去之后才不会覆盖在图片之上。即使我们给文字设置margin负值也不会起作用。

是什么意思呢?就是背景可以重叠,但是内容不重叠。其实还是整个元素往上浮动了。

float与absolute脱离文档流的区别

使用float脱离文档流时,其他盒子会无视这个元素,但其他盒子内的文本依然会为这个元素让出位置,环绕在周围。

.firstdiv{
  background-color:rgba(125,125,235,0.4);
  height:200px;
  width: 200px;
  float: left;
}
.seconddiv{
  background-color: #faf;
  height:300px;
  width: 300px;
  border:1px solid red;
}
<div class="firstdiv">
   这是第一个DIV
</div>
<div class="seconddiv">
   这是第二个DIV
</div>

根据chrome调试和红色边框,可以看到第二个div的背景和边框是占据了第一个DIV的空间的,但是第二个div的文本仍然为第一个DIV留出了位置。

css39.jpg

对于使用absolute position脱离文档流的元素,其他盒子与其他盒子内的文本都会无视它。

例如:将上例中float:left改为position: absolute。可以看到,第二个div的文字亦被第一个div的文字给覆盖了

css40.jpg