css面试点-BFC(块级格式化上下文)与常见布局方案

1,570 阅读6分钟

定位方案

常见的定位方案,定位方案是控制元素的布局,有三种常见方案:

  • 普通流 (normal flow)
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行,除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
  • 浮动 (float)
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
  • 绝对定位 (absolute positioning)
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。

什么是BFC:

  • BFC是一个独立的布局环境,其中的元素布局是不受外界的影响,并且在一个BFC中,块盒与行盒(行盒由一行中所有的内联元素所组成)都会垂直的沿着其父元素的边框排列。
  • 可以把 BFC 理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。
  • 浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks table-cells 和 table-captions),以及overflow值不为visiable的块级盒子,都会为他们的内容创建BFC(块级格式化上下文)。

BFC触发条件:

  【1】根元素,即HTML元素

  【2】float的值不为none

  【3】overflow的值不为visible (overflow的其他值:hidden、auto、scroll)

  【4】display的值为inline-block、table-cell、table-caption、flow-root、flex或者inline-flex

  【5】position的值为absolutefixed

BFC布局规则:

1.内部的Box会在垂直方向,一个接一个地放置(不设置浮动,设置浮动那肯定是左右一行排列了)。

2.Box垂直方向的距离由margin决定。属于同一个BFC两个相邻Box的margin会发生重叠(正常的不设置浮动,两个块元素margin重叠,仅仅是垂直方向,左右不是这个样子的),会发生外边距合并,指的是当两个垂直外边距相遇时,它们将形成一个外边距。合并后的外边距的高度等于两个发生合并的外边距的高度中的较大者。

3.每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。(不设置浮动,不设置左边距,块级子元素,一律靠左竖直向下排列,内联子元素一律从左向右排列,想想,正常写代码,都是这样,设置左浮动的靠近父元素的左边,设置右浮动,靠近父元素的右边。)

4.BFC的区域不会与float盒子重叠。BFC区域的子元素不受外面的影响,外面的也不受BFC区域里面的影响(这个挺重要的,设置的浮动的元素,脱离了文档流,正常的相邻的元素会跑到它下面(靠左)。设置成BFC,自己独成一块,不会跑到它下面,自己依然占一块。)

5.计算BFC的高度时,浮动元素也参与计算(就是子元素设置浮动,脱离文档流,父元素高度塌陷,给父元素设置BFC,那么父元素高度就不会忽略浮动的子元素,从而高度就不会塌陷,这样理解,好像是BFC又把脱离文档流的元素,又拉回来了,但保持了浮动的特点。)

BFC主要用途:

外边距折叠

<div class="container">
  <p>Sibling 1</p>
  <p>Sibling 2</p>
</div>

.container {
  background-color: red;
  overflow: hidden;
}
p {
  background-color: lightgreen;
  margin: 10px 0;
}

在上图中,一个红盒子(div)包含着两个兄弟元素(p),一个BFC已经创建了出来。
理论上,两个p元素之间的外边距应当是二者外边距之和(20px)但实际上却是10px,这是外边距折叠(Collapsing Margins)的结果。
产生折叠的必备条件:margin必须是邻接的。

在CSS当中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可以结合成一个单独的外边距。这种合并外边距的方式被称为折叠,并且因而所结合成的外边距称为折叠外边距

外边距折叠(外边距合并)的计算方式
1、两个相邻的外边距都是正数时,折叠结果是它们两者之间较大的值。
2、两个相邻的外边距都是负数时,折叠结果是两者绝对值的较大值。
3、两个外边距一正一负时,折叠结果是两者的相加的和。

利用BFC避免外边距折叠

<div class="container">
  <p>Sibling 1</p>
  <div class="container1">  
      <p>Sibling 2</p>
  </div>
</div>

.container {
  background-color: red;
  overflow: hidden;
}
p {
  background-color: lightgreen;
  margin: 10px 0;
}
.container1{
  overflow: hidden;
}
因为第一个和第二个P元素现在分属于不同的BFC,它们之间就不会发生外边距折叠了。

BFC清除浮动

浮动元素是会脱离文档流的(绝对定位元素会脱离文档流)。如果一个没有高度或者heightauto的容器的子元素是浮动元素,则该容器的高度是不会被撑开的。我们通常会利用伪元素(:after或者:before)来解决这个问题。BFC能包含浮动,也能解决容器高度不会被撑开的问题。

<div class="container">
    <div>Sibling</div>
    <div>Sibling</div>
</div>

.container {
    background-color: blue;
    overflow: hidden; // 添加后才能实现BFC,才能包住浮动元素
}
.container div {
    float: left;
    background-color: lightgreen;
    margin: 10px;
}
未添加overflow: hidden

添加overflow: hidden

阻止元素被浮动元素覆盖

<div style="height: 100px;width: 100px;float: left;background: lightblue">
    我是一个左浮动的元素 one
</div>
<div style="width: 200px; height: 200px;background: grey">
    我是一个没有设置浮动,也没有触发 BFC,我想你这次只是生气时间久了一点,是的。
</div>

<div style="height: 100px;width: 100px;float: left;background: lightblue">
    我是一个左浮动的元素 two
</div>
<div style="width: 200px; height: 200px;background: grey;overflow:hidden">
    我是一个没有设置浮动,触发 BFC 元素,我想你这次只是生气时间久了一点,是的。
</div>
由于左侧块级元素发生了浮动,所以和右侧未发生浮动的块级元素不在同一层内,所以会发生div遮挡问题。可以给右侧元素添加 overflow: hidden,触发BFC来解决遮挡问题。