相信大家和我一样,第一次听到别人说CSS 块级格式化上下文(block formatting context,简称:BFC)的时候一头雾水,为了帮助大家弄清楚块级格式化上下文,我翻阅了W3C的CSS规范,把和块级格式化上下文有关的资料整理了出来。

  先介绍一下普通流,普通流就是我们口中常说的文档流。在CSS 2.1的规范中有两段关于普通流的描述:

Normal flow. In CSS 2.1, normal flow includes block formatting of block-level boxes, inline formatting of inline-level boxes, and relative positioning of block-level and inline-level boxes.

  普通流包括了块格式化,行内格式化,相对定位。

Boxes in the normal flow belong to a formatting context, which may be block or inline, but not both simultaneously. Block-level boxes participate in a block formatting context. Inline-level boxes participate in an inline formatting context.

  在普通流中框属于一种格式化上下文,类型可以是block或者是inline,但不能同时属于这两者。块级框(Block-level boxes)参与在块级格式化上下文中,行内框(Inline-level boxes)参与在行内格式化上下文中。

  根据上面两段话我们可以知道,普通流把不同类型的框划分给了不同的格式化上下文,块级格式化上下文就是其中之一。

  再来看看规范是怎么描述格式化上下文的:

  A formatting context is the environment into which a set of related boxes are laid out.Different formatting contexts lay out their boxes according to different rules.

  格式化上下文是布置一组相关框的环境,不同的格式化上下文,根据不同的规则布置自己的框。

  看了这段定义,我们可以清晰的知道块级格式化上下文是什么了:它是一个布置块级框的环境,这个环境有它自己特有的规则。块级框被普通流划分给了块级格式化上下文,然后块级框按照块级格式化上下文的规则呈现在了页面上。

  块级格式化上下文的规则通过规范的这两句话表达了出来:

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the 'margin' properties. Vertical margins between adjacent block-level boxes in a block formatting context collapse.

In a block formatting context, each box's left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box's line boxes may shrink due to the floats), unless the box establishes a new block formatting context.

  在BFC中,块级框在它的容器块中从上往下依次排列。两个块级框之间的垂直距离由margin属性决定,在同一个块级格式化上下文中垂直方向上的margin会被重叠(collapse)

  在BFC中,每个块级框左边紧贴容器块的左边缘(书写从右向左的话,紧贴右边缘)。这种情况即使在有浮动元素存在的情况下也会发生,除非块级框创建一个新的格式化上下文。

  现在我们可以总结一下BFC的特性了:

  1. 如果给一个元素创建了一个BFC,就相当于创建了一个新的环境,环境内和环境外中的元素不会相互影响。外边的BFC规则,不会对环境里的块级框产生影响,而容器里面的规则也不会对环境外的块级框产生影响,也就是相互隔绝,互不影响。
  2. 块级框的布局是从包含容器的顶部开始的,从上往下依次排列。
  3. 在同一个BFC中,两个相邻的块级元素的垂直margin会发生重叠(collapse)。
  4. 每个块级框的边界都要紧靠包含容器的边界,即使块级框的遇到浮动元素,当块级框创建一个新的BFC的时候,这个特性不生效。

  第一条和第二条非常容易理解,就不细说了。第三条和第四条特性,我们在工作中应该都遇到过,可能不清楚css效果背后的原理,这里给大家细说一下。 先说第三条,请看下面代码,元素A和元素B是相邻的兄弟元素,元素B有个子元素C,元素A的底部margin与元素B的顶部margin发生了重叠,元素C的顶部margin与元素A、B的margin也发生了重叠。因为此时元素A、元素B、元素C都属于同一个BFC中(这个BFC就是根元素所创建),而且他们的垂直margin互相接触了,所以发生了重叠。

  <div id="A" style="background: #f1f2f3; margin-bottom: 20px;">
我是A
</div>
<div id="B" style="background: #f1f2f3; margin-top: 20px;">
<div id="C" style="background: red; width: 30px; height: 20px; margin-top: 20px;">我是C</div>
</div>

  代码效果如下所示

我是A
我是C

  这个时候可以设置overflow: auto让B元素创建一个新的BFC,这样元素A就属于元素B新创建的BFC中,就不会发生margin重叠,而元素A和元素B依然同处于同一个BFC中,所以元素A与元素B依然会发生margin重叠。还有很多别的方式阻止margin重叠,这里只关注和BFC有关的内容。

我是A
我是C

  还有一种特殊的margin重叠也与BFC有关,就是空元素自身的顶部margin和底部margin发生了重叠:    

  <div id="container">
<div style="background: #f1f2f3; height: 20px;">我是占位置的</div>
<div id="emptyElementMarginCollapse" style="margin: 20px 0;"></div>
<div style="background: #f1f2f3; height: 20px;">我是占位置的</div>
</div>

   空元素顶部margin和底部margin各有20px,而实际间距只有20px,并不是40px,是因为margin产生了重叠。大家可以自己试一下,博客园编辑器会自动在空元素中插入一个空格,这里就不做代码演示了。此时只需要在空元素上设置overflow:auto创建一下新的格式化上下文,空元素的margin重叠就会消失。和BFC有关的margin重叠问题就是这些了,接下来我们看第四条特性。

  第四条特性和浮动有关,从表现上来看就是我们常说的文字环绕效果,请看下面代码,一个块级元素里面有两个浮动元素,含有文字的块级框的布局完全无视浮动元素,它的左右边界紧贴在包含容器的边缘:

  <div style="width: 400px;border: 1px solid;">
<div style="float: left;width:100px;height: 100px;background-color: #ddd;">float:left;</div>
<div style="float: right;width:100px;height: 100px;background-color: #ddd;">float:right;</div>
<div style="background-color: #f1f2f3;">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima vero aperiam error expedita, tempore nemo obcaecati ipsam incidunt ipsa fugiat! Doloribus delectus, illum nisi. Maxime labore asperiores, inventore in est.</div>
</div>
float:left;
float:right;
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima vero aperiam error expedita, tempore nemo obcaecati ipsam incidunt ipsa fugiat! Doloribus delectus, illum nisi. Maxime labore asperiores, inventore in est.

  现在让我们在含有文字的块级元素上创建一个新的BFC

<div style="width: 400px;border: 1px solid;">
<div style="float: left;width:100px;height: 100px;background-color: #ddd;">float:left;</div>
<div style="float: right;width:100px;height: 100px;background-color: #ddd;">float:right;</div>
<div style="background-color: #f1f2f3;overflow: auto;">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima vero aperiam error expedita, tempore nemo obcaecati ipsam incidunt ipsa fugiat! Doloribus delectus, illum nisi. Maxime labore asperiores, inventore in est.</div>
</div>
float:left;
float:right;
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima vero aperiam error expedita, tempore nemo obcaecati ipsam incidunt ipsa fugiat! Doloribus delectus, illum nisi. Maxime labore asperiores, inventore in est.

  正如规范中所说的一样,一个块级框新建了一个BFC之后,它遇到浮动元素就不会紧贴父元素的边缘了。

  BFC的特性都介绍完了,接下来该介绍如何创建BFC了,这里我给大家整理了一下,格式化上下文的创建方式:

  • 根元素或其它包含它的元素
  • 浮动元素 (元素的 float 不是 none)
  • 绝对定位元素 (元素具有 position 为 absolute 或 fixed)
  • 内联块 (元素具有 display: inline-block)
  • 表格单元格 (元素具有 display: table-cell,HTML表格单元格默认属性)
  • 表格标题 (元素具有 display: table-caption, HTML表格标题默认属性)
  • 具有overflow 且值不是 visible 的块元素
  • display: flow-root
  • column-span: all 应当总是会创建一个新的格式化上下文,即便具有 column-span: all 的元素并不被包裹在一个多列容器中。

  BFC的创建方式有很多种,最常用的就是通过设置overflow属性和设置绝对定位来创建,因为设置overflow属性对整体布局的影响比较小。

  看到这里,相信大家对于BFC不在陌生,对BFC有了一个清晰的认知,不过内容还没结束,浮动元素与BFC真的只有这点关系嘛?回想一下浮动塌陷问题的解决方案,其中有一个方案通过给父容器设置overflow:hidden来解决浮动塌陷的问题,因为设置overflow:hidden会创建一个新的BFC,那这个方案的背后是不是与BFC也有关系呢?没错,这个的确和BFC有关系,但是这并不是BFC的特性,而是height设置为auto的特性,它的特性受到了BFC所影响,CSS2.1 规范中有这样一段话:

  In certain cases, the height of an element that establishes a block formatting context is computed as follows: 

(此处省略三段) 

  In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge, then the height is increased to include those edges. Only floats that participate in this block formatting context are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not.

  在某些情况下,建立了BFC的元素的高度应该按照以下规则计算:如果元素含有浮动的子元素,这些子元素底边缘在父元素底边缘的下面,那么父元素的高度提升到可以包含这些子元素。只有参与了BFC的浮动元素才会考虑,在绝对定位和浮动元素内部的浮动元素不会考虑。

  咱们先看代码以及效果:

  <div style="border: 1px solid;">
<div style="background: #f1f2f3; height: 20px; width: 20px; float: left;">
<div style="background: rgb(18, 7, 230); height: 40px; width: 20px; float: left;margin-left: 30px;"></div>
</div>
</div>

  文本编辑器竟然不允许两个浮动元素嵌套,这里我只能用图片来展示效果了,希望大家都能自己运行一下代码,看看效果。

  

  对比图中的效果,完全印证了规范里所说的内容。一开始最外层div元素内部只有浮动元素,由于浮动元素脱离普通流,导致了高度塌陷,最外层div元素高度为0。然后给最外层div元素设置了overflow:auto,创建了一下新的格式化上下文,然后新的规则生效了。新规则指出,当块级元素height为auto时,如果块级元素内部有浮动元素,并且浮动元素的底边缘比块级容器元素还低,那么提高块级容器元素的高度,直到它可以包含这些浮动元素,所以最外层的div元素的高度变成了20px。最里面蓝色的浮动元素高度为40px,它的位置是在浮动元素内部,属于例外情况,最外层的div元素不需要包含它,所以它的高度不会影响到最外层div的高度。

  到此为止,有关BFC的内容就都讲完了,总结一下,BFC就是普通流中的由一系列规则组成的影响块级框布局的环境,这个环境可以通过设置一些css属性来触发。BFC影响着外边距重叠、浮动塌陷、元素重叠,在写css的时候需要主意一下。希望看完这篇文章的你对于BFC不再是一头雾水。

  

  非常感谢您的阅读,文中如有不对的地方,欢迎指正交流!

详解块级格式化上下文(BFC)的更多相关文章

  1. css中margin重叠和一些相关概念(包含块containing block、块级格式化上下文BFC、不可替换元素 non-replaced element、匿名盒Anonymous boxes )

    平时在工作中,总是有一些元素之间的边距与设定的边距好像不一致的情况,一直没明白为什么,最近仔细研究了一下,发现里面有学问:垂直元素之间的margin有有互相重叠的情况:新建一个BFC后,会阻止元素与外 ...

  2. 块级格式化上下文(BFC)

    一.什么是BFC 具有BFC属性的元素也属于普通流定位方式,与普通容器没有什么区别,但是在功能上,具有BFC的元素可以看做是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且具有普通容 ...

  3. 块级格式化上下文(block formatting context)、浮动和绝对定位的工作原理详解

    CSS的可视化格式模型中具有一个非常重要地位的概念——定位方案.定位方案用以控制元素的布局,在CSS2.1中,有三种定位方案——普通流.浮动和绝对定位: 普通流:元素按照先后位置自上而下布局,inli ...

  4. BFC 详说 Block Formatting Contexts (块级格式化上下文)

    定位方案是控制元素的布局,在 CSS 2.1 中,有三种定位方案——普通流 (Normal Flow) .浮动 (Floats) 和绝对定位 (Absolute Positioning) ,下面分别对 ...

  5. Block Formatting Contexts (块级格式化上下文) 详解

         最近在学习BootStrap框架,发现里面清除浮动的类 .clearfix 跟平时自己用的不太一样.它的样式是这样的: .clearfix:before { content: " ...

  6. 详说 Block Formatting Contexts (块级格式化上下文)

    在上文<详说清除浮动>中,Kayo 较为详细地介绍了 BFC ,也就是本文的主角 Block Formatting Contexts (块级格式化上下文),本文会基于上文关于 BFC 的部 ...

  7. CSS2系列:BFC(块级格式化上下文)IFC(行级格式化上下文)

    BFC 块级格式化上下文,不好理解,我们暂且把她理解成"具有特殊的一类元素" 哪些元素会生成BFC? 根元素 float属性不为none position为absolute或fix ...

  8. BFC(Box,Formatting,Context) —— 块级格式化上下文

    Box:CSS布局的基本单位 Formatting context是页面中的一块渲染区域,最常见的是BFC和IFC,CSS3增加了GFC和FFC BFC定义:块级格式化上下文,它是一个独立的渲染区域, ...

  9. BFC块级格式化上下文简述

    做过页面编写的各位应该对定位不陌生了,这个样式表中的重头戏,也是最难把控的元素之一,今天在这里我们要讲到的就是与浮动与清除浮动相关的定位元素,对于定位有很多种,有绝对定位,还有相对定位,固定定位,静态 ...

随机推荐

  1. uni-app——想说爱你不容易之踩坑系列

    1.uni-app不支持动态组件,目前在用i-if判断,或者用scroll-view切换,没有想到什么其他的办法 2.uni-app不支持具名插槽,会导致页面塌陷 3.uni-app在做动态组件渲染的 ...

  2. pins-模块内的代码及资源隔离方案

    随着项目的不断迭代,复杂的业务模块及项目自身的基础技术组件迅速扩张,以往基于单个模块的项目往往显得过于臃肿.代码目录结构,包名混乱,代码模块职责不清晰,耦合度高,不便维护.基础公共组件没有抽取并剥离干 ...

  3. Spring Boot入门(二):使用Profile实现多环境配置管理&如何获取配置文件值

    在上一篇博客Spring Boot入门(一):使用IDEA创建Spring Boot项目并使用yaml配置文件中,我们新建了一个最原始的Spring Boot项目,并使用了更为流行的yaml配置文件. ...

  4. Java基础练习3(重载和重写)

    1.(多选题)给定java代码如下所示,在1处新增下列()方法,是对show()方法的重载 public class Test{ public void show(int x, int y, int ...

  5. MySQL8.0新特性——支持原子DDL语句

    MySQL 8.0开始支持原子数据定义语言(DDL)语句.此功能称为原子DDL.原子DDL语句将与DDL操作关联的数据字典更新,存储引擎操作和二进制日志写入组合到单个原子事务中.即使服务器在操作期间暂 ...

  6. 学习ELk之----02. Elastic Search操作入门

    我们将使用Postman来进行日志写入操作.Postman的下载地址,你可以Google一下. 1. 在上一节中,我们启动完成ELK的Docker后,可以在浏览器中打开:http://192.168. ...

  7. zookeeper3.4.13集群安装

    环境: Centos7.6 Zookeeper3.4.13 Java1.8 安装前准备 安装java 官网下载jdk-8u201-linux-x64.tar.gz 备用 三台主机:192.168.2. ...

  8. ASP.NET Aries 高级开发教程:Excel导入之单表配置(上)

    前言: 随着ASP.NET Aries的普及,刚好也有点闲空,赶紧把Excel导入功能的教程补上. Excel导入功能,分为四篇:单表配置(上).多表高级配置(中).配置规则(下).代码编写(番外篇) ...

  9. 关于单元测试的思考--Asp.Net Core单元测试最佳实践

    在我们码字过程中,单元测试是必不可少的.但在从业过程中,很多开发者却对单元测试望而却步.有些时候并不是不想写,而是常常会碰到下面这些问题,让开发者放下了码字的脚步: 这个类初始数据太麻烦,你看:new ...

  10. Docker & ASP.NET Core (3):发布镜像

    第一篇:把代码连接到容器 第二篇:定制Docker镜像 上一篇文章最后有个问题,定制的镜像无法正常运行: 这可能是由于无法找到要运行的dll引起的问题. 之前的Dockerfile的文档我是按照微软的 ...