相信大家和我一样,第一次听到别人说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. react源码总览(翻译)

    用react也有段时间了, 是时候看看人家源码了. 看源码之前看到官方文档 有这么篇文章介绍其代码结构了, 为了看源码能顺利些, 遂决定将其翻译来看看, 小弟英语也是半瓢水, 好多单词得查词典, 不当 ...

  2. [译]PEP 342--增强型生成器:协程

    PEP原文 : https://www.python.org/dev/peps/pep-0342/ PEP标题: Coroutines via Enhanced Generators PEP作者: G ...

  3. VS2017、VS2019没有Setup安装项目(Visual Studio Installer)_解决方案

    前言: VS2010中有一个自带的安装部署项目,叫:Visual Studio Installer ,我们通常称为:setup项目,是一个用于自定义安装部署的项目方案.但是在VS2017,VS2019 ...

  4. 关于ef+codefirst+mysql/dapper(dbFirse)(入门)

    ef+mssql详细是许多.net程序员的标配.作为一个程序员当然不能只会mssql这一个数据库,今天简单聊聊ef+mysql.推荐新人阅读. 1]首先创建一个mvc项目,如图: 创建完毕之后再nug ...

  5. 004. 前端跨域资源请求: JSONP/CORS/反向代理

    1.什么是跨域资源请求? https://www.cnblogs.com/niuli1987/p/10252214.html 同源: 如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有 ...

  6. 二、redis命令简单使用(不区分大小写)

    key  * 查看redis中的所有键(当键的数量较多会影响性能,不建议生产环境中使用) exists  key 判断一个键是否存在,存在返回1,否则返回0 del  key  [key...] 删除 ...

  7. 判断HTML中的checkbox是否被选中

    //合法性验证 function checkValidity() { var userNameCheck = $("#userNameCheck").attr('checked') ...

  8. 前端项目中常用es6知识总结 -- 箭头函数及this指向、尾调用优化

    项目开发中一些常用的es6知识,主要是为以后分享小程序开发.node+koa项目开发以及vueSSR(vue服务端渲染)做个前置铺垫. 项目开发常用es6介绍 1.块级作用域 let const 2. ...

  9. Vue.js-02:第二章 - 常见的指令的使用

    一.前言 在上一章中,我们了解了一些在使用 Vue 进行开发中经常会遇到的基础概念,与传统的前端开发不同,Vue 可以使我们不必再使用 JavaScript 去操作 DOM 元素(还是可以用,但是极度 ...

  10. ubuntu16.04无法获取ip地址的解决方案

    当我们无法获取ip地址时可以使用dhcp来动态获取ip地址,安装dhcpcd5和dhcpcd-gtk sudo apt-get install dhcpcd5 sudo apt-get install ...