BFC及其特性详解

  1. 什么是BFC
    BFC(Block Formatting Context)块级格式化上下文,w3c文档描述:

9.4 Normal flow
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.

  1. 产生BFC
    1)根元素(默认情况下只有根元素,即body一个块级上下文)
    2)浮动元素,floatnone 以外的值;
    3)定位元素,positionabsolutefixed
    4)displayinline-blocktable-celltable-caption其中之一;
    5)overflowhiddenautoscroll
    w3c文档描述:

9.4.1 Block formatting contexts
Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with ‘overflow’ other than ‘visible’ (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

  1. BFC特性
    1)内部的盒子(Box)会在垂直方向上一个接一个的放置;
    2)垂直方向上的距离由margin决定,属于同一个BFC的两个相邻的块级元素会发生margin合并,不属于同一个BFC的两个相邻的块级元素不会发生margin合并
    3)每个盒子的左边,与包含块的左边相接触(从右往左的格式,右边缘接触)。即使存在浮动也是如此,除非产生了新的BFC
    4)BFC的区域不会与float box重叠;
    5)BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素;外面的元素也不会影响到容器里面的子元素;
    6)计算BFC的高度时,浮动元素也参与计算
    w3c文档描述:

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

对这几个特性解释一下:
1)内部的盒子(Box)会在垂直方向上一个接一个的放置:还没有理解,以后补充;
2)垂直方向上的距离由margin决定,属于同一个BFC的两个相邻的块级元素会发生margin合并,不属于同一个BFC的两个相邻的块级元素不会发生margin合并
看一个例子:例1

//CSS
#div1 {
    border: 1px solid #000099;
    height: 60px;
    width: 200px;
    margin-bottom:20px;
    background: red;
}
#div2 {
    border: 1px solid #000099;
    height: 60px;
    width: 200px;
    margin-top: 30px;
    background: blue;
}
//HTML

BFC及其特性详解_第1张图片
#div1#div2属于同一个BFC(body),因此发生了margin折叠,基于此,取消折叠也很简单,可以让他们属于不同的BFC:例2

//HTML
<body>
<div id='par-div'><div id='div1'>div>div>
<div id='div2'>div>
body>
//CSS
#par-div {
    overflow: hidden;  //也可以使用其他的方式,依需求而定
}

BFC及其特性详解_第2张图片
3)每个盒子的左边,与包含块的左边相接触(从右往左的格式,右边缘接触)。即使存在浮动也是如此,除非产生了新的BFC

可以参考https://segmentfault.com/q/1010000008875016,解释的很好。

要先理解包含块的概念。包含块不是一个完整的box,一个完整的box包含margin-boxborder-boxpadding-boxcontent-box。即使设置为0,也是存在的。

包含块有可能是某个盒子的content-box,也有是某个盒子的padding-box。这取决于被包含块所包含的盒子的position属性。

例如:如果某个盒子 position 属性是 absolute 的话,包含块就由盒子最近的祖先元素(position 的值不是 staticfixed, absolute, relative, or sticky))的padding-box组成。简单的说,就是当使用子绝父相定位的时候,位置是相对于包含块而言的,也就是父元素的padding-box

又例如:某个盒子 position 属性是 staticrelative 的话,包含块就由它的最近的祖先块元素的content-box的边缘组成的。简单的说,默认定位的盒子,其包含块就是块级父元素的content-box

再例如,positionfixed 盒子的包含块为视口。简单的说,固定定位盒子你怎么滚动始终在所看到的窗口上。w3c原文描述:

10.1 Definition of “containing block”
The position and size of an element’s box(es) are sometimes calculated relative to a certain rectangle, called the containing block of the element. The containing block of an element is defined as follows:
(1)The containing block in which the root element lives is a rectangle called the initial containing block. For continuous media, it has the dimensions of the viewport and is anchored at the canvas origin; it is the page area for paged media. The ‘direction’ property of the initial containing block is the same as for the root element.
(2)For other elements, if the element’s position is ‘relative’ or ‘static’, the containing block is formed by the content edge of the nearest ancestor box that is a block container or which establishes a formatting context.
(3)If the element has ‘position: fixed’, the containing block is established by the viewport in the case of continuous media or the page area in the case of paged media.
(4)If the element has ‘position: absolute’, the containing block is established by the nearest ancestor with a ‘position’ of ‘absolute’, ‘relative’ or ‘fixed’, in the following way:
1)In the case that the ancestor is an inline element, the containing block is the bounding box around the padding boxes of the first and the last inline boxes generated for that element. In CSS 2.2, if the inline element is split across multiple lines, the containing block is undefined.
2)Otherwise, the containing block is formed by the padding edge of the ancestor.
If there is no such ancestor, the containing block is the initial containing block.

有了包含块的概念,再回过头去看w3c中的关于BFC的英文原文。

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).

原文第一句翻译,在一个bfc中,每一个盒子的左外边距应该和包含块的左边接触。这句话有两个地方值得注意

第一、 bfc中的盒子应该与其自身的包含块相接触,而非与bfc盒子相接触,这个包含块有可能是bfc中的一部分,也有可能和bfc无关。

第二、bfc中的盒子是与其包含块的 left edge 相接触,而不是包含块的left-border相接触。因为包含块并非一个完整的盒子,不可能有left-border。 left edge 正确的翻译为左边缘。

第二句翻译:即使存在浮动盒子也应该如此(如此的意思就是布局应该按照上述的规则进行),除非子盒子又形成了一个新的bfc。

这句话正确的理解方式为,一个bfc中,如果存在一个浮动的盒子,而其他盒子并没有形成新的bfc,那么所有的子盒子都应该触碰到其包含块的左边缘。举个例子,一个父盒子使用overflow:hidden形成bfc,其中有个子盒子,一个浮动,另一个不浮动。那么浮动盒子会盖住不浮动盒子,但是两个盒子都会触碰到bfc的content-box。例3:

//css
#div1 {
    float: left;
    height: 60px;
    width: 100px;
    background: red;
}
#div2 {
    height: 160px;
    width: 200px;
    background: blue;
}
//HTML
<body>
<div id='div1'>我是第一个div>
<div id='div2'>我是第二个div>
body>

BFC及其特性详解_第3张图片
如果BFC里有两个浮动的盒子,第二个盒子会追在第一个盒子屁股后面,是不是违反规范了?答案是没有,第二句话说的很明白,除非盒子自身又形成了一个新的bfc,第二个盒子使用浮动,不就形成了一个新的bfc了吗。还是上面那个例子,将#div2形成BFC:例4

//css
#div2 {
    float: left;
    height: 160px;
    width: 200px;
    background: blue;
}

BFC及其特性详解_第4张图片
4)BFC的区域不会与float box重叠;
指的是,BFC盒子内部的区域,也就是BFC盒子的子元素,不会影响到float box元素及其内部子元素,并不是指BFC盒子本身
例5

//css
#div1 {
    float: left;
    height: 60px;
    width: 100px;
    background: red;
}
#div2 {
    overflow: hidden;
    height: 160px;
    width: 200px;
    background: blue;
}
//html
<div id='div1'>
    <p>我是第一个p>
div>
<div id='div2'>我是第二个div>

BFC及其特性详解_第5张图片
可以看出,#div2并没有影响#div1

//css
#div1 {
    float: left;
    height: 60px;
    width: 100px;
    background: red;
}
#div2 {
    position: absolute;
    height: 60px;
    width: 35px;
    background: blue;
}
//html
<div id='div1'>
    <p>我是第一个p>
div>
<div id='div2'>我是第二个div>

BFC及其特性详解_第6张图片
可以看出,#div2虽然覆盖了并没有影响#div1

6)计算BFC的高度时,浮动元素也参与计算
我们知道,若父元素没有设置高度,当子元素float时,父元素不会被撑开:例6

//css
img {
	float: right;
}
div {
    border: 1px solid;
}
<p>在下面的段落中,添加了 <b>float:rightb> 的图片。导致图片将会浮动在段落的右边。p>
<div>
	<img src="/attachments/cover/cover_css.png" width="95" height="84" />
	<p>这是一些文本。这是一些文本。这是一些文本。p>
div>

BFC及其特性详解_第7张图片
因此可以利用BFC的这个特性,为父元素设置overflow:hidden,代码如下:

//css
div {
    border: 1px solid;
    /* 具体使用哪个要看界面设计的情况 */
    /* overflow: hidden; */
    /* display:inline-block; */
    /* position:absolute; */
    overflow: hidden;
}

BFC及其特性详解_第8张图片
最后说一下,BFC盒子一般就3个用途,不要自己搞得很复杂:

1、清除浮动,比如设置了overflow:hidden;、position:absolute;、float:left;的元素,【其内部】的浮动会被清除(注意清除浮动说的都是float产生的浮动,position:absolute|fixed那不叫浮动)

2、修复margin折叠

3、两栏布局自适应,仅overflow+float有效
参考资料

[1] https://www.w3.org/TR/CSS21/visuren.html
[2] https://segmentfault.com/q/1010000008875016
[3] https://www.jianshu.com/p/7e04ed3f4bea

你可能感兴趣的:(BFC,css)