聊聊CSS基础盒模型、理解块格式化上下文(BFC)

1,456 阅读8分钟

什么是块格式化上下文(BFC),需要先了解几个知识点。

基础框盒模型(basic box model)

盒模型

当浏览器在对一个文档进行布局的时候,浏览器的渲染引擎会根据CSS基础框盒模型(CSS basic box model),将所有元素都转化为一个个矩形的盒子(box),盒子的大小、外观等属性是由CSS来决定。

每一个盒子都由四个部分组成,由于内而外分别是内容区域(content area)内边距区域(padding area)边框区域(border area)外边距区域(margin area)

两种盒模型

盒模型有两种标准,一种是W3C的标准盒模型,一种是IE的盒模型。

W3C标准盒模型中,width指的是content的宽度
IE标准盒模型中,width指的是content + padding + border这三部分组成的宽度

默认情况下使用的是标准盒模型,CSS中可以通过box-sizing来切换盒模型

  • box-sizing: content-box W3C标准盒子模型
  • box-sizing: border-box IE盒模型

视觉格式化模型(visual formatting model)

CSS 视觉格式化模型(visual formatting model)是用来处理并且在视觉媒体上显示文档时使用的计算规则。视觉格式化模型会根据CSS盒子模型将文档中的元素转换为一个个盒子。

块级盒子

元素的display属性设置为block、list-item或者table的时候,该元素就称为块级元素(block-level element),每个块级元素至少会生成一个块级盒子(block-level box),每个块级盒子都会参与块格式化上下文的创建。

行内盒子

元素的display属性设置为inline、inline-block或者inline-table的元素就称为行内级元素(inline-level element)行内级盒子(inline-level box)由行内级元素生成,参与行内格式化上下文创建的行内级盒子称为行内盒子(inline box)

匿名块盒子

某些情况下,在进行视觉格式化的时候,需要添加一些増补性的盒子,这些盒子不能用CSS选择符选中,所以称为匿名盒子(anonymous box),CSS选择器不能作用于匿名盒子,所以它不能被样式表赋予样式,因此所有可继承的CSS属性值都为inherit,而所有不可继承的CSS属性值都为initial。以下例子可以产生匿名块盒子:

<div>文本文本文本文本<p>p标签包含的内容</p>文本文本文本文本</div>

对于这两个匿名盒子来说,我们无法通过CSS选择符选中并添加样式,因此它们会从div那里继承那些可继承的属性,比如font-size、color等。

定位规则

普通流

  • 在普通流的块格式化上下文中,盒子会垂直依次排列
  • 在普通流的行内格式化上下文中,盒子会水平依次排列
  • 对于静态定位,即position为static时,每个盒子会根据普通流所计算出的确切位置来定位
  • 对于相对定位,即position为relative时,每个盒子还会根据属性top、bottom、left和right在原本所在的位置上发生指定大小的偏移,不管这个盒子偏移距离多远,原来的位置都不会被其他元素占用

浮动

浮动定位的盒子,会浮动到当前所在行的开始位置或者结尾位置,普通流中的其他内容会“流”到浮动盒子的边缘处,除非元素通过clear清除前面的浮动。

绝对定位

如果盒子的position属性为absolute或者fixed,则该盒子为绝对定位盒子。绝对定位的盒子会完全脱离文档流,不占据空间,可以与其他元素重叠,不会与其他元素有任何联系,可以通过属性top、bottom、left和right对绝对定位盒子进行位置调整,而且该盒子的位置只相对他最近并且具有定位(absolute、relative或者fixed)的父元素而言,如果没有已定位的父元素,那么它的位置就相对于<html>

块格式化上下文(BFC)

块格式化上下文(Block Formatting Context,BFC),是一个独立的渲染区域,拥有一套渲染规则来约束这个区域中元素的布局,该区域中元素的布局不会受到外界的影响。

创建块格式化上下文(BFC)

  • 根元素(<html>)
  • 浮动元素(元素的float不为none)
  • 绝对定位元素(元素的position为absolute或者fixed)
  • 行内块元素(元素的display为inline-block)
  • 表格单元格(元素的display为table-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的display为table-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的display为table、table-row、table-row-group、table-header-group、table-footer-group(分别是HTML table、row、tbody、thead、tfoot的默认属性)或inline-table)
  • overflow值不为visible的块元素
  • display值为flow-root的元素

(引用自MDN Web 文档

块格式化上下文(BFC)的布局规则

1. 在BFC中,盒子从顶端沿着垂直方向一个接一个地排列

2. 两个盒子之间的垂直间隙是由他们的margin值所决定的,在同一个BFC中,两个相邻的块级盒子的垂直外边距会产生重叠。

3. 在BFC中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)。对于从右到左的格式来说,则是右外边缘触碰到容器的右边缘。即使存在浮动也是一样的。

4. BFC区域不会和float的盒子重叠。

5. 计算BFC区域高度的时候,所有元素包括float元素都要参与计算

6. BFC在页面上是一个隔离的独立容器,容器里面的子元素不会影响到外面的元素

块格式化上下文(BFC)的作用

第一个例子

<body>
    <div class="box1"></div>
    <div class="box2"></div>
</body>
.box1 {
    width: 100px;
    height: 100px;
    background-color: khaki;
 }
.box2 {
    width: 200px;
    height: 200px;
    background-color: powderblue;
 }

BFC布局规则的第一条,在BFC中,盒子从顶端沿着垂直方向一个接一个地排列

第二个例子

<body>
    <div class="box1"></div>
    <div class="box2"></div>
</body>
.box1 {
    width: 100px;
    height: 100px;
    background-color: khaki;
    margin: 20px;
 }
.box2 {
    width: 200px;
    height: 200px;
    background-color: powderblue;
    margin: 20px;
 }

根据BFC布局规则第二条,两个盒子之间的垂直间隙是由他们的margin值所决定的,在同一个BFC中,两个相邻的块级盒子的垂直外边距会产生重叠。

我们现在要防止margin重叠,我们将box2包裹在另一个BFC中,给box2添加一个父容器并将这个父容器转变为BFC

.box2-parent {
    overflow: auto;
  }
<div class="box2-parent">
  <div class="box2"></div>
</div>

第三个例子

<body>
    <div class="box1"></div>
    <div class="box2"></div>
</body>
body {
    border: 2px solid green;
  }
.box1 {
    width: 100px;
    height: 100px;
    background-color: khaki;
    float: left;
  }
.box2 {
    width: 200px;
    height: 200px;
    background-color: powderblue;
  }

根据BFC布局规则的第三条,在BFC中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)。对于从右到左的格式来说,则是右外边缘触碰到容器的右边缘。即使存在浮动也是一样的。

根据BFC布局规则的第四条,BFC区域不会和float的盒子重叠。

我们把第三个例子中的box2转变为BFC,根据BFC的创建规则overflow值不为visible的块元素,给box2添加overflow: auto;

.box2 {
    width: 200px;
    height: 200px;
    overflow: auto;
    background-color: powderblue;
  }

我们会发现BFC区域没有和float盒子重叠。

第四个例子

<div class="wrapper">
  <div class="box1"></div>
  <div class="box2"></div>
</div>
.wrapper {
    border: 2px solid green;
 }
.box1 {
    width: 100px;
    height: 100px;
    float: left;
    background-color: khaki;
 }
.box2 {
    width: 200px;
    height: 200px;
    float: left;
    background-color: powderblue;
 }

我们发现这样做会造成wrapper容器高度塌陷,我们根据BFC布局规则第五条,计算BFC区域高度的时候,所有元素包括float元素都要参与计算,把wrapper容器转变为BFC,给wrapper添加display属性,值为flow-root。

.wrapper {
    border: 2px solid green;
    display: flow-root;
  }

以上例子同时也体现了BFC布局规则的第六条,BFC在页面上是一个隔离的独立容器,容器里面的子元素不会影响到外面的元素

结语

学无止境,学习各位前辈的经验,不断提升自己的能力,本文是笔者花了差不多一周的时间针对BFC这一块知识点进行学习之后做的文章记录,如果有什么不足或错误的地方,请大家多多指点!谢谢大家的阅读!

参考文章

前端精选文摘:BFC 神奇背后的原理
我对BFC的理解
学习 BFC (Block Formatting Context)
前端进阶之什么是BFC?BFC的原理是什么?如何创建BFC?
MDN 块格式化上下文   MDN 视觉格式化模型   MDN CSS 基础框盒模型介绍
W3C Block formatting contexts