详情地址:块级格式化上下文 Block formatting context (BFC)
1. Box
视觉格式化模型会根据CSS盒子模型将文档中的元素转换为一个个盒子。盒子主要包括了块盒、行内盒、匿名盒(没有名字不能被选择器选中的盒)以及一些实验性的盒(未来可能添加到规范中)。盒的类型由display属性决定。
(1)块盒
- 当元素的display为block、list-item或table时,该元素将成为块级元素。
- 显示时,竖直排列。
- 每个块级元素都会至少生成一个块级盒子, 称为主要块级盒(principal block-level box)。一些元素,比如<li>,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。
- 每个块级盒子都会参与块格式化上下文(block formatting context)的创建。
- 一个块级盒子可能也是一个块容器盒子。块容器盒子(block container box)要么只包含其它块级盒子,要么只包含行内盒子并同时创建一个行内格式化上下文(inline formatting context)。
- 一个同时是块容器盒子的块级盒子称为块盒子(block box )。
(2)行内盒
- 如果一个元素的display属性为inline、inline-block或inline-table,则称该元素为行内级元素。
- 显示时,它不会生成内容块,但是可以与其他行内级内容一起显示为多行。如包含多种格式内容(如强调文本、图片等)的段落,就可以由行内级元素组成。
- 行内级元素会生成行内级盒子,该盒子同时会参与行内格式化上下文(inline formatting context)的创建。
- 行内盒子既是行内级盒子,也是一个其内容会参与创建其容器的行内格式化上下文的盒子,比如所有具有display:inline样式的非替换盒子。
- 如果一个行内级盒子的内容不参与行内格式化上下文的创建,则称其为原子行内级盒子。而通过替换行内级元素或 display值为 inline-block或 inline-table的元素创建的盒子不会像行内盒子一样可以被拆分为多个盒子。
(3)匿名盒
匿名盒也分匿名块盒与匿名行内盒,因为匿名盒没有名字,不能利用选择器来选择它们,所以它们的所有属性都为inherit或初始默认值。
比如:
<div>
Some inline text
<p>followed by a paragraph</p>
followed by more inline text.
</div>
(4)其他
行盒子、Run-in 盒子,这里就不介绍了
2. FC(Formatting context)
Formatting context(格式化上下文)是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的Formatting context有Block fomatting context(BFC)和Inline formatting context(IFC)。CSS2.1 中只有BFC和IFC, CSS3中还增加了GFC和FFC。
3. BFC(Block fomatting context)
BFC是一个独立的渲染区域,只有块级盒子(Block-level box)参与, 它规定了内部的块级盒子(Block-level box)如何布局,并且与这个区域外部毫不相干。
一个BFC包含创建该上下文元素的所有子元素,但不包括创建了新BFC的子元素的内部元素。
4. BFC布局规则
- 内部的Box会在垂直方向,一个接一个地放置;
- Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠;
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此;
- BFC的区域不会与float box重叠;
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此;
- 计算BFC的高度时,浮动元素也参与计算。
5. 创建BFC的常见方法
- 根元素(<html>)
- 浮动元素(元素的float不是none)
- 绝对定位元素(元素的position为absolute或fixed)
- 行内块元素(元素的display为inline-block)
- 表格单元格(元素的display为table-cell,HTML表格单元格默认为该值)
- overflow值不为visible的块元素
- 弹性元素(display为flex或inline-flex元素的直接子元素)
- 网格元素(display为grid或inline-grid元素的直接子元素)
其中最常见的就是overflow:hidden、float:left/right、position:absolute。每次看到这些属性的时候,就代表了该元素创建了一个BFC。
6. BFC的作用
(1)自适应两栏布局
.left{
width: 200px;
height: 400px;
background-color: #A694DB;
float: left;
}
.right{
height: 600px;
background-color: #dfd8f8;
}
<div class="wrap">
<div class="left">
</div>
<div class="right">
</div>
</div>
效果如下:
显然,上述的效果是满足BFC布局规则的:每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
可以看到如果.left不出现浮动,那么两个div会垂直摆放,且它们的margin box的左边居于包含块(这里是body)的border box的左边相接触,如果.left出现了浮动,两个div叠在了一起,但是它们仍然满足这一规则。
那么,我们在实现两栏布局时,希望两个div不重叠,我们可以根据BFC布局规则:BFC的区域不会与float box重叠,来实现这一效果,我们触发div.right生成一个BFC这样,它就不会与浮动的div重叠,如下(只需要修改.right的样式):
.right{
height: 600px;
background-color: #dfd8f8;
overflow: hidden;
}
效果:
(2)清除浮动
.wrap{
border: 2px solid red;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
float: left;
}
.p2{
float: left;
width: 50px;
height: 50px;
background: #aa55ff;
}
<div class="wrap">
<p class="p1">1</p>
<p class="p2">2</p>
</div>
我们知道,浮动的元素会脱离文档流,这样会造成父元素的高度塌陷问题。如下:
前面我们介绍了BFC的布局规则,其中最后一条:计算BFC的高度时,浮动元素也参与计算。
显然,我们利用BFC可以来解决父元素高度塌陷问题,我们可以触发父元素div.wrap生成一个BFC,这样计算父元素高度时,浮动元素也会参与计算,不会出现高度塌陷的问题。如下:修改div.wrap的CSS样式即可
.wrap{
border: 2px solid red;
/* overflow: hidden; */
display: flex;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
float: left;
}
.p2{
float: left;
width: 50px;
height: 50px;
background: #aa55ff;
}
效果如下:
(3)防止垂直margin重叠
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
margin-bottom: 20px;
}
.p2{
margin-top: 10px;
width: 50px;
height: 50px;
background: #aa55ff;
}
<body>
<p class="p1">1</p>
<p class="p2">2</p>
</body>
根据BFC布局的第二个规则:Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠。如下:两个p标签的距离是20px,发生了margin重叠
显然,要解决这个问题,我们可以将两个P标签放在不同的BFC中,这样他们的margin就不会发生重叠了。如下,我们给第一个P标签添加一个父容器,并触发父容器生成一个BFC,那么这次两个P标签就属于不同的BFC中了。
.wrap{
/* display: flex; */
/* overflow: hidden; */
display: inline-block;
}
.p1{
width: 50px;
height: 50px;
background: #55AAFF;
margin-bottom: 20px;
}
.p2{
margin-top: 10px;
width: 50px;
height: 50px;
background: #aa55ff;
}
<div class="wrap">
<p class="p1">1</p>
</div>
<p class="p2">2</p>
效果:
参考