BFC到底是个什么东东?

FC

FC是Formatting Context的简写,直译过来是格式化上下文。其实并非什么复杂的东西,我的对于它的理解是:FC就是html页面中的某个元素内的一套渲染规则,决定了其子元素如何布局,以及和其余元素在html页面中的位置css

好比说BFC, BFC是block formatting context,也就是块级格式化上下文,是用于布局块级盒子的一块渲染区域,举个例子来讲就是一个position为absolute(触发BFC的条件之一)的div就是一个BFC。html

常见的FC还有前端

  • IFC(inline formatting context,即内联级元素内的渲染规则
  • GFC(grid formatting context,display为grid的元素内的渲染规则)
  • FFC(flex formatting context,display为flex的元素内的渲染规则)。

什么是触发XFC(x表明B,I,G,F其中之一)?

即经过设置某个元素的某些属性值来使得该元素应用某种渲染规则。例如将一个div的display属性设置为grid,那么就称触发了GFC,该元素内就造成了一个GFC,该元素内的渲染规则就要使用GFC规则segmentfault

BFC

如何触发BFC?

即如何让某元素内造成BFC环境浏览器

某个元素知足下列条件之一就可造成一个BFCapp

  1. 该元素是根元素,即<html></html>标签内就是一个BFC环境
  2. float的值不为none
  3. overflow的值不为visible
  4. display的值为inline-block、table-cell、table-caption
  5. position的值为absolute或fixed

BFC的渲染机制(BFC特性)

1.在块格式化上下文中,从包含块的顶部开始,垂直地一个接一个地排列盒子。

In a block formatting context, boxes are laid out one after the other, vertically, beginning at the top of a containing block.less

第一条特性我以为描述得并不严谨,应该是块级盒子会在垂直方向上一个接一个放置布局

那什么是块级盒子呢?下面是w3c文档对块级盒子的描述flex

Block-level elements are those elements of the source document that are formatted visually as blocks (e.g., paragraphs). The following values of the 'display' property make an element block-level: 'block', 'list-item', and 'table'.this

块级元素是那些在源文档中可视为块的元素(如,段落p标签)。display属性为以下属性的元素是块级元素:blocklist-item, table

Block-level boxes are boxes that participate in a block formatting context. Each block-level element generates a principal block-level box that contains descendant boxes and generated content and is also the box involved in any positioning scheme. Some block-level elements may generate additional boxes in addition to the principal box: 'list-item' elements. These additional boxes are placed with respect to the principal box.

其大体意思: 块级盒子就是那些参与块级格式化上下文的盒子(废话-_-)。每一个块级元素都会产生一个主要的块级盒子来容纳子元素和生成的内容,而且是定位模式中会涉及到的元素(我的理解就是块级盒子会影响元素的位置)。一些块级元素也可能产生除主要盒子以外的附属盒子好比list-item(li)元素

Except for table boxes, which are described in a later chapter, and replaced elements, a block-level box is also a block container box. A block container box either contains only block-level boxes or establishes an inline formatting context and thus contains only inline-level boxes. Not all block container boxes are block-level boxes: non-replaced inline blocks and non-replaced table cells are block containers but not block-level boxes. Block-level boxes that are also block containers are called block boxes.

除了后面一章描述的table盒子和替换元素(浏览器根据元素的标签和属性,来决定元素的具体显示内容。如img和input标签)以外,块级盒子也是块级容器盒子(注意二者的区别)。一个块级容器盒子要么只容纳块级盒子,要么就会创建内联格式化上下文,所以也只容纳内联级盒子(个人理解:一个盒子要么是块级盒子,要么就是内联级盒子)。并非全部的块级容器盒子都是块级盒子: 非替换内联块和单元格(td, th)不是块级盒子。既是块级盒子,同时又是块级容器才能被称为块盒子。(最后一句我也是醉了,在下水平有限,不能get到原文想要表达的意思)

The three terms "block-level box," "block container box," and "block box" are sometimes abbreviated as "block" where unambiguous.

“块级盒子”、“块容器盒子”和“块盒子”这三个术语有时在没有歧义的时候能够简写为“块”,(这句话一开始我理解错了,感谢@Tipwheal的指正!)

那什么是没有歧义的时候呢?我的理解是“块级盒子”、“块容器盒子”和“块盒子”都是指块级盒子的时候能够简写为块,即diplay为block的元素。(笔者也不太肯定,若是有朋友理解,但愿您能在评论中留言)

2.垂直方向上的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。

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.

这个垂直方向上的距离由margin决定通俗易懂,不须要赘述。属于同一个BFC的两个相邻Box的margin会发生重叠

这个重叠主要会有两种状况: 1.上下相邻的两个元素 2.父元素与子元素的margin发生重叠

上下相邻的两个元素的margin会重叠

重叠的规则是:二者之间的垂直方向上的距离取决于谁的margin大

验证一下

.top, .btm {
  width: 200px;
  height: 200px;
}
.top {
  margin-bottom: 20px;
  background: deepskyblue;
}
.btm {
  margin-top: 30px;
  background: darkorange;
}
复制代码
<div id="app">
    <div class="top"></div>
    <div class="btm"></div>
</div>
复制代码

这个时候top与btm之间的距离不是50px,而是30px

左边的图中间的部分是top的margin-top,右边的图的中间部分是btm的margin-top,能够看到二者的距离就是btm的margin-top的距离

那么问题来了,怎么消除上下margin重叠呢?

给须要去除margin重叠的上下元素加float属性

.top, .btm {
  width: 200px;
  height: 200px;
  float:left;
  clear: both; /* 使元素可以垂直排列 */ 
}
.top {
  margin-bottom: 20px;
  background: deepskyblue;
}
.btm {
  margin-top: 30px;
  background: darkorange;
}
复制代码

也能够用border,padding替代margin达到想要的效果。

我认为上下相邻的两个元素的margin重叠是没有必要消除的,除非想要实现某些效果时才须要消除

父元素与子元素的margin发生重叠

若是父元素的margin-top为0,padding-top为0,没有border,而子元素的margin-top不为0,那么父元素距离上方的距离就会是子元素margin-top的值,margin-bottom同理

举个栗子

* {
  padding: 0;
  margin: 0;
}
#app {
  background: yellowgreen;
}

.top {
  background: deepskyblue;
  height: 200px;
  margin: 20px;
}
.footer {
  height: 200px;
  width: 200px;
  background: yellow;
}
复制代码
<div id="app">
    <div class="top"></div>
</div>
<div class="footer"></div>
复制代码

能够看到父元素app因为top与上下都产生了外边距

消除父子margin重叠的方法:

  1. 给父元素加border
  2. 设置父元素的padding或者margin
  3. 给父元素添加overflow:hidden

3.bfc的区域不会与float的元素区域重叠。

<div class="left"></div>
<div class="main"></div>
复制代码
.main {
  background: deepskyblue;
  width: 400px;
  height: 400px;
}
.left {
  float: left;
  width: 200px;
  height: 200px;
  background: darkorange;
}
复制代码

浏览器渲染的结果以下所示

main与left产生了重叠

而当设置overflow:hidden

.main {
  background: deepskyblue;
  width: 400px;
  height: 400px;
  overflow: hidden;
}
复制代码

就消除了float的影响

利用float能够造成文字环绕效果,可是也能够利用这条特性消除文字环绕效果

4.在块格式化上下文中,每一个box的左外边缘都与包含块的左边缘相接触(对于从右到左的格式化,右边缘相接触)

在块格式化上下文中,每一个box的左外边缘都与包含块(注意这个名词)的左边缘相接触(对于从右到左的格式化,右边缘相接触)。即便在浮动存在的状况下也是如此(尽管box的box's line boxes 可能会由于浮动而收缩),除非box创建了一个新的块格式上下文(在这种状况下,box自己可能会由于浮动而变得更窄)。

原文是这样的

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 (in which case the box itself may become narrower due to the floats).

这段话在网上解释的中文版本很是多,因而就产生了歧义

真正要理解这句话首先要搞懂一个概念,什么是包含块?

In CSS 2.1, many box positions and sizes are calculated with respect to the edges of a rectangular box called a containing block. In general, generated boxes act as containing blocks for descendant boxes; we say that a box "establishes" the containing block for its descendants. The phrase "a box's containing block" means "the containing block in which the box lives," not the one it generates.

在CSS 2.1中,许多盒子的位置和大小是根据一个矩形框(称为包含块)的边缘来计算的。一般,生成的盒子充当包含子盒子的块;咱们说一个盒子为它的后代“创建”了包含它的块。短语“a box's contains block”的意思是“盒子所在的包含块”,而不是它生成的块。

Each box is given a position with respect to its containing block, but it is not confined by this containing block; it may overflow.

每一个盒子都被赋予相对于其包含块的位置,但不受该包含块的限制;它可能溢出。

那么是否是全部元素的包含块就是其父元素的content-box呢?

答案固然是:不是!!

只能说,大多数状况下,包含块就是这个元素最近的祖先块元素的内容区。某个元素的包含块与其直接父元素有可能一点关系都没有。举一个例子:一个position为absolute的元素,包含块就是由它的最近的 position 的值不是 static (fixed, absolute, relative, or sticky)的祖先元素的内边距区的边缘组成的。若是要深刻研究请参考这篇文章我所了解的包含块

在懂了包含块的概念以后咱们再来看这条特性,就豁然开朗。

那么即便在浮动存在的状况下也是如此,这个该怎么理解呢?咱们知道当给元素设置float以后,只要宽度足够,元素就会一个接一个横向排列,那从第二个元素起,岂不是不会接触包含块的边缘了?是否是文档错了呢?

文档的下文还写着除非box创建了一个新的块格式上下文,而给元素添加float属性就会造成新的BFC,因此文档的描述是很精确的

5.计算bfc的高度时,浮动元素也参与计算

这条特性就是就是解决子元素浮动致使父元素没法撑开的关键

.main {
  background: deepskyblue;
}
.main div {
  height: 100px;
  width: 100px;
  float: left;
}
复制代码
<div class="main">
    <div></div>
    <div></div>
</div>
复制代码

上面的渲染结果为页面一片空白...

而让class为main的父级div造成BFC后

.main {
  background: deepskyblue;
  position: absolute;  /* 触发BFC */
}
复制代码

渲染结果以下:

父元素就被撑开了。而且position设置为absolute的块级元素的width是不会占满剩余空间,若是不设置宽度而且没有子元素,其宽度为0,若是有子元素,其宽度由子元素撑开

6.bfc就是页面上的一个独立容器,容器里面的子元素不会影响外面元素。

这个特性通俗易懂,不须要解释

总结

咱们能够用BFC机制完成的事情:

  1. 清除浮动的影响
  2. 清除margin重叠

ps:本人前端小菜鸟一只,若是文中有错,欢迎各位看客可以指正

相关文章
相关标签/搜索