块级格式化上下文 Block formatting context (BFC)

详情地址:块级格式化上下文 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>

效果:

 

参考

视觉格式化模型 | MDN

块格式化上下文| MDN

学习块格式化上下文| 博客园

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章