BFC

2021-6-7 CSS

BFC && 外边距折叠

# BFC

BFC(Block fomatting context) = block-level box + Formatting Context

# Box

  • Box即盒子模型
  • block-level box即块级元素,display属性为block,list-item,table的元素,会生成block-level box;并参与block formatting content
  • inline-level box即行内元素,display属性为inline,inline-block,inline-table的元素,会生成inline-level box;并参与inline formatting content

# Formatting content

  • 这是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系、相互作用。最常见的有BFC(B为Block)和IFC(I为inline)。
  • CSS2.1中只有BFC和IFC,CSS3中还增加了GFC(G为grid)和FFC(F为flex)。

# BFC定义

​ BFC直译为“块级格式化上下文”。它是一个独立的渲染区域,只有block-level box参与,它规定了内部的block-level box如何布局,并且与这个区域外部毫不相干。

# BFC的生成

​ 上文提到BFC是一块渲染区域,那这块渲染区域到底在哪,它有多大,这些由生成BFC的元素决定,CSS2.1中规定满足下列CSS声明之一的元素便会生成BFC。

  • html根元素
  • float的值不为none
  • overflow的值不为visible
  • display的值为inline-block、table-cell、table-caption
  • display的值为flex或inline-block、grid或inline-grid元素的直接子元素
  • position的值为absolute或fixed
  • contain的值为layout、content或paint

:display: table也认为可以生成BFC,因为table默认生成一个匿名的table-cell,正是这个匿名的table-cell生成了BFC。

# BFC的特性及应用

  1. 同一个BFC下外边距会发生折叠
<head>
  <style>
    div{
        width: 100px;
        height: 100px;
        background: lightblue;
        margin: 50px;
    }
  </style>
</head>
<body>
  <div></div>
  <div></div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

如上代码,两个div元素都处于同一个BFC容器下(这里指html元素),所以两个div的外边距发生了重叠,如果想要避免外边距的重叠,可以将其放在不同的BFC容器中

<head>
  <style>
  	.box{
  		overflow: hidden;
  	}
    .box1{
        width: 100px;
        height: 100px;
        background: lightblue;
        margin: 50px;
    }
  </style>
</head>
<body>
  <div class="box">
  	<div class="box1"></div>
  </div>
  <div class="box">
  	<div class="box1"></div>
  </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  1. BFC可以包含浮动元素

当容器内的元素浮动时,就会脱离文档流,且有时会发生父元素高度塌陷的情况

<head>
  <style>
    .box {
      border: 5px solid lightcoral;
    }

    .box1 {
      width: 100px;
      height: 100px;
      background: lightblue;
      float: left;
    }
  </style>
</head>

<body>
  <div class="box">
    <div class="box1"></div>
  </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

如果触发容器的BFC,那么容器将会包裹浮动元素(如给.box添加display: inline-block;)

  1. BFC可以阻止元素被浮动元素覆盖

先看一个文字环绕的效果:

<head>
  <style>
    .box {
      width: 200px;
      height: 200px;
      background-color: lightcoral;
    }

    .box1 {
      width: 100px;
      height: 100px;
      background-color: lightblue;
      float: left;
    }
  </style>
</head>

<body>
  <div>
    <div class="box1">
      我是一个浮动的元素
    </div>
    <div class="box">
      我没有设置浮动,也没有触发BFC,假装这里文字很多,假装这里文字很多,假装这里文字很多,假装这里文字很多
    </div>
  </div>
</body>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

可以看到第二个div有部分被浮动元素遮挡,但文本信息会环绕着浮动元素,如果想避免元素被覆盖,可触发第二个元素的BFC特性,在.box中添加overflow: hidden;就会变成如下效果:

该方法可以用来实现两栏自适应布局,利用float+overflow:hidden;,主要思想是通过overflow触发BFC,而BFC不会与浮动元素重叠。由于设置overflow:hidden;并不会触发IE6-浏览器的haslayout属性,所以需要设置zoom:1来兼容。

# 外边距折叠

定义:块的顶部和底部边距有时被合并(折叠)成单个边距,其大小是各个边距中的最大值。外边距折叠是在垂直方向上,水平方向不会发生折叠。

# 外边距折叠的几种情况

  • 相邻的两个元素之间的外边距会折叠(除非后一个元素需要清除之前的浮动)
  • 在父元素与其第一个子元素之间不存在边框、内边距、行内元素,也没有创建BFC、或者清除浮动将两者的margin-top分开,此时子元素的外边距会“溢出”到父元素外面
  • 在父元素与其最后一个子元素之间不存在边框、内边距、行内元素、height、min-height、max-height将两者的margin-bottom分开,此时子元素的外边距会“溢出”到父元素外面

# 如何避免外边距叠加

  1. 浮动元素、inline-block元素、绝对固定定位元素的margin不会和垂直方向上其他元素的margin折叠
  2. 创建了块级格式化上下文的元素,不和它的子元素发生margin折叠

:触发了BFC的元素只是与其子元素不发生margin折叠,但和其上下相邻元素的margin还是会折叠。