BFC
什么是BFC,触发它的条件,应用
什么是BFC
BFC—Block formatting context ,直译为”块级格式化上下文”。
1.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.
2.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.
3.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.浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的BFC(块级格式上下文)。
2.在一个块级格式化上下文里,盒子从包含块的顶端开始垂直地一个接一个地排列,两个盒子之间的垂直的间隙是由他们的margin 值所决定的。两个相邻的块级盒子的垂直外边距会发生叠加。
3.在块级格式化上下文中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘),即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个盒子创建一个新的块级格式化上下文(这种情况下,由于浮动,盒子本身将会变得更窄)。
补充解释上文出现的两个词 box、formatting context
Box: CSS布局的基本单位
Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。元素的类型和 display 属性,决定了这个 Box 的类型。 不同类型的 Box, 会参与不同的 Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。让我们看看有哪些盒子:
- 1、Block-level elements and block boxes
1)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’.
翻译:
1)块级元素是那种源文档被格式化为可视块(例如,段落)了的元素,然后使这个元素变成块级元素的display属性取值如下: ‘block’, ‘list-item’, 和 ‘table’。
2)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
翻译:
2)块级盒block-level box是这种参与了块级排版上下文的一种盒子,每个块级元素都生成了一个包含后代盒子和生成的内容的主要块级盒,并且这个盒子参与了任何定位的计算
总结:
block-level box:display 属性为 block, list-item, table 的元素,会生成 block-level box。并且参与 block fomatting context;
- 2、Inline-level elements and inline boxes
1)Inline-level elements are those elements of the source document that do not form new blocks of content; the content is distributed in lines (e.g., emphasized pieces of text within a paragraph, inline images, etc.). The following values of the ‘display’ property make an element inline-level: ‘inline’, ‘inline-table’, and ‘inline-block’. Inline-level elements generate inline-level boxes, which are boxes that participate in an inline formatting context.
2)An inline box is one that is both inline-level and whose contents participate in its containing inline formatting context. A non-replaced element with a ‘display’ value of ‘inline’ generates an inline box. Inline-level boxes that are not inline boxes (such as replaced inline-level elements, inline-block elements, and inline-table elements) are called atomic inline-level boxes because they participate in their inline formatting context as a single opaque box.
总结:
inline-level box:display 属性为 inline, inline-block, inline-table 的元素,会生成 inline-level box。并且参与 inline formatting context;
https://www.w3.org/TR/CSS21/visuren.html#box-gen
css3中 Types of boxes 新增如下box类型:
- compact boxes
- Marker boxes
- Run-in boxes
https://www.w3.org/TR/css3-box/#run-in-boxes
Formatting context
https://www.w3.org/TR/CSS21/visuren.html#normal-flow
Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。
Block formatting contexts
Inline formatting contexts
CSS2.1 中只有 BFC 和 IFC, CSS3 中还增加了 GFC 和 FFC。本文此处知讨论BFC,IFC等以后再详细研究。
BFC的通俗理解:
1.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。(这里面的不会影响,只在文档流内是不会影响的,脱离文档流后,当忽略)
2.BFC是Web页面中盒模型布局的CSS渲染模式。它的定位体系属于常规文档流。
Positioning schemes:
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.
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.
在普通流中的 Box(框) 属于一种 formatting context(格式化上下文) ,类型可以是 block ,或者是 inline ,但不能同时属于这两者。并且, Block boxes(块框) 在 block formatting context(块格式化上下文) 里格式化, Inline boxes(块内框) 则在 inline formatting context(行内格式化上下文) 里格式化。
任何被渲染的元素都属于一个 box ,并且不是 block ,就是 inline 。即使是未被任何元素包裹的文本,根据不同的情况,也会属于匿名的 block boxes 或者 inline boxes。所以上面的描述,即是把所有的元素划分到对应的 formatting context 里。
生成BFC的条件
w3.org官方给出的定义总结了一个BFC是怎样形成的,一个BFC是一个HTML盒子并且至少满足下列条件中的任何一个:
- 根元素
- float属性不为none
- position为absolute或fixed
- display为inline-block, table-cell, table-caption, flex, inline-flex
- overflow不为visible(hidden,auto,scroll )
CSS3里面对BFC做了改动,称之为: flow root ,并且对触发条件进行了进一步说明。 https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Block_formatting_context
理解触发BFC的条件:
- 根元素
html文档建立,就会触发根元素的BFC,我们在根元素内写几个div元素,会发现内部div垂直排列,本身没有兄弟元素,内部块级盒子来自同一个BFC(html),所以相邻margin会重叠,行内盒子横向就不会重叠。
- float属性不为none
当一个元素被设置为float:left or right,会触发这个元素,生成BFC区域,使他不仅拥有BFC的渲染规则,而且会给自身带来副作用,display:block,但是这个元素不会像行内元素通过设置display:block变为块级元素那样,宽度充满其父元素,而是表现的更像行内块级元素,只会使得行内元素不会收缩包裹其内容.
- position为absolute或fixed
这个触发器触发生成BFC后,margin重不重叠这个对于他都没有效果,绝对定位流和普通文档流、浮动流不属于一个,,所以自然会与浮动元素重叠。
BFC布局规则【BFC的原理】
- 内部的Box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
BFC的特性
1、BFC会阻止垂直外边距(margin-top、margin-bottom)折叠;
Collapsing margins
1.1 根据 CSS 2.1 8.3.1 Collapsing margins 第一条,
In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.
Two margins are adjoining if and only if:
-
both belong to in-flow block-level boxes that participate in the same block formatting context
-
no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。也就是处于同一个BFC中的两个垂直窗口的margin会重叠。 这个包括相邻元素,嵌套元素,只要他们之间没有阻挡(例如边框,非空内容,padding等)就会发生margin重叠。
1.2 根据 CSS 2.1 8.3.1 Collapsing margins 第三条,
Margins of elements that establish new block formatting contexts (such as floats and elements with ‘overflow’ other than ‘visible’) do not collapse with their in-flow children.
生成BFC的元素不会和在流中的子元素发生空白边折叠。所以解决这种问题的办法是要为两个容器添加具有BFC的包裹容器。
2、创建了 Block Formatting Context 的元素不能与浮动元素重叠;
表格的 border-box、块级的替换元素、或是在普通流中创建了新的 block formatting context(如元素的 ‘overflow’ 特性不为 ‘visible’ 时)的元素不可以与位于相同的 block formatting context 中的浮动元素相重叠。
3、Block Formatting Context就是页面上的一个隔离的独立容器,容器里面的子元素不会在布局上影响到外面的元素,反之也是如此;
4、BFC可以包含浮动,且浮动子元素应该参与其高度计算;
根据CSS2.1 规范第10.6.7部分的高度计算规则,
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.
在计算生成了 block formatting context 的元素的高度时,其浮动子元素应该参与计算。
BFC应用
不和浮动元素重叠-overlap
使用BFC来防止文字环绕
自适应两栏布局
首先我们来看浮动实现文字环绕的效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<style>
*{
margin:0;
padding: 0;
}
.wrap{
width: 400px;
margin:20px auto;
}
.aside{
float: left;
width: 140px;
height: 140px;
background: #f60;
}
.main{
/*overflow: hidden;*/
height: 200px;
background: #93f;
}
</style>
<body>
<div class="wrap">
<div class="aside">float:left</div>
<div class="main">文字环绕效果</div>
</div>
</body>
</html>
result display
验证开篇定义BFC的第三条:
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
因此,虽然存在浮动的元素aslide,但main的左边依然会与包含块的左边相接触。
那么怎样让main和aside不重叠?
根据BFC的区域不会与float box重叠。
我们可以通过通过触发main生成BFC,来实现自适应两栏布局,或者防止文字环绕效果。
.main {
overflow: hidden;
}
result display
当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。
防止垂直 margin 重叠
我们先来看看,同一个BFC中的两个垂直窗口的margin发生的重叠现象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<style>
*{
margin:0;
padding: 0;
}
.wrap{
width: 400px;
margin:20px auto;
border: 1px solid red;
}
p{
height:20px;
margin: 20px 0;
background: #fcc;
}
</style>
<body>
<div class="wrap">
<p>1</p>
<p>2</p>
<p>3</p>
</div>
</body>
</html>
result display
如果他们属于不同的BFC,他们之间的外边距将不会折叠。
因此,我们可以在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<style>
*{
margin:0;
padding: 0;
}
.wrap{
width: 400px;
margin:20px auto;
border: 1px solid red;
}
.contain{
overflow: hidden;
/*border: 1px solid red;*/
}
p{
height:20px;
margin: 20px 0;
background: #fcc;
}
</style>
<body>
<div class="wrap">
<p>1</p>
<p>2</p>
<div class="contain">
<p>3</p>
</div>
</div>
</body>
</html>
result display
番外篇:
还有一个对父元素进行border的设置也可以解决父子元素margin重叠的问题。
清除元素内部浮动-clear
我们先来看内部元素浮动,对外部元素带来高度塌陷的现象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<style>
*{
margin:0;
padding: 0;
}
.wrap{
/*overflow: hidden;*/
/*position: absolute;*/
/*float: left;*/
width: 400px;
margin:20px auto;
border: 1px solid red;
}
.box{
float: left;
width: 100px;
height: 100px;
margin-right: 10px;
background: #399;
}
</style>
<body>
<div class="wrap">
<div class="box">float: left;</div>
<div class="box">float: left;</div>
</div>
</body>
</html>
result display
根据上述BFC的特性第4条:
计算生成了 block formatting context 的元素的高度时,其浮动子元素应该参与计算。
所以,我们可以触发外部容器BFC,高度将重新计算。比如给outer加上属性overflow:hidden
触发其BFC。
result display
使用BFC的其它局限 :
1.float:left 父容器float解决了其塌陷问题,且浮动元素本身BFC化,带来浮动元素有破坏性和包裹性,那么父容器的父容器怎么办?
2.position:absolute 这个脱离文档流有些严重;
3.overflow:hidden 有剪裁和出现滚动条等隐患,我们可以在确定不会有什么被剪裁的情况下,很happy地使用。
在多列布局中使用BFC
.fix + .l/.r + .cell
的无敌组合
.clearfix {
*zoom: 1;
}
.clearfix:after {
content: '';
display: table;
clear: both;
}
.float-left {
float: left;
margin-right: 20px;
}
.cell {
display: table-cell;
*display: inline-block;
width: 9999px;
*width: auto;
}
完整例子参照上节float浮动布局最后一个demo4.2
如果是局部,且确认安全;或有连续英文字符换行的隐患,你也可以使用.fix + .l/.r + .ovh
的无敌组合,可以多栏,也可以无限嵌套。