BFC 背后的布局问题
BFC 是前端面试中的一个超级热点,今日头条某部门曾经就问过
请解释一下 回答这个问题并不困难,但是可以继续追问
BFC 是什么
简单来说,BFC 就是
Block Formatting Context 的简写,可以直接翻译成「」
而 BFC 的一套特点和规则就规定了在这个特殊的区域中
- 如何进行布局
- 如何进行定位
- 区域内元素的相互关系和相互作用
- 并且这个特殊的区域不受外界影响
上面提到了 block box
的概念,block box
是指 display
属性为 block
、list-item
、table
的元素
相应地,还有 inline box
,它是指 display
属性为 inline
、inline-block
、inline-table
的元素
如何形成 BFC
那么
MDN 总结如下
- 根元素或其他包含它的元素
- 浮动元素(元素的
float
不是none
) - 绝对定位元素(元素具有
position
为absolute
或fixed
) - 内联块(元素具有
display: inline-block
) - 表格单元格(元素具有
display: table-cell
,HTML 表格单元格默认属性) - 表格标题(元素具有
display: table-caption
, HTML 表格标题默认属性) - 具有
overflow
且值不是visible
的块元素 display: flow-root
的元素column-span: all
的元素
BFC 决定了什么
上面谈到了 BFC 的一套规则,那么这些
总结如下
- 内部的
box
将会独占宽度,且在垂直方向,一个接一个排列 box
垂直方向的间距由margin
属性决定,但是同一个 BFC 的两个相邻box
的margin
会出现边距折叠现象- 每个
box
水平方向上左边缘,与 BFC 左边缘相对齐,即使存在浮动也是如此 - BFC 区域不会与浮动元素重叠,而是会依次排列
- BFC 区域内是一个独立的渲染容器,容器内元素和 BFC 区域外元素不会形成任何干扰
- 浮动元素的高度也参与到 BFC 高度的计算当中
从这些规则中,至少能总结出一些 ,比如
- 边距折叠
- 清除浮动
- 自适应多栏布局
理解了 BFC,这些常见、常考知识点都可以融会贯通,具体来看下下面的场景
BFC 实战应用
例题 1
给出如下代码:
<style>
body {
width: 600px;
position: relative;
}
.left {
width: 80px;
height: 150px;
float: left;
background: blue;
}
.right {
height: 200px;
background: red;
}
</style>
<body>
<div class="left"></div>
<div class="right"></div>
</body>
得到布局如图:
请在不修改已有内容情况下,加入样式,实现自适应(.left
宽度固定,.right
占满剩下宽度)两栏布局
- 根据 BFC 布局规则
- 「」
- 因此
.left
和.right
的左边相接触,出现如此布局结果并不意外
- 同时,再想想 BFC 布局规则
- 「」
- 因此可以使
.right
形成 BFC,来实现自适应两栏布局
于是添加
.right {
overflow: hidden;
}
就可以得到
当然,这种布局可以用更先进的 flex
或者 grid
手段解决,但是对于 BFC 这些 CSS 基础知识,同样要做到了然于胸
例题 2
看代码
<style>
.root {
border: 5px solid blue;
width: 300px;
}
.child {
border: 5px solid red;
width: 100px;
height: 100px;
float: left;
}
</style>
<div class="root">
<div class="child child1"></div>
<div class="child child2"></div>
</div>
首先来回答第一个问:.root
的高度是多少?
事实上,因为 .child
为浮动元素,因此造成了「」现象,.root
的高度为 0
那么如何解决「高度塌陷」问题呢?
- 想想 BFC 规则
- 「」
- 因此使
.root
形成 BFC,就能解决问题
.root {
overflow: hidden;
}
此时高度已经被撑开了
例题 3
代码
<style>
p {
color: blue;
background: red;
width: 400px;
line-height: 100px;
text-align: center;
margin: 40px;
}
</style>
<body>
<p>paragraph 1</p>
<p>paragraph 2</p>
</body>
首先回答问题:两段之间的垂直距离为多少?
- 想想 BFC 规则
- 「」
- 事实上,因为边距折叠现象,答案为
40px
- 那么如何解决这个问题呢?
- 最简单地,可以在
p
标签再包裹一个元素,并触发该元素形成一个 BFC - 那么这两个
p
标签,不再属于同一个 BFC,从而解决问题
- 最简单地,可以在
<style>
p {
color: blue;
background: red;
width: 400px;
line-height: 100px;
text-align: center;
margin: 40px;
}
.wraper {
overflow: hidden;
}
</style>
<body>
<p>paragraph 1</p>
<div class="wraper">
<p>paragraph 2</p>
</div>
</body>
总结:通过分析 BFC 是什么、如何形成、布局规则,融会贯通了 CSS 当中很多关键问题
也许不少开发者能够解决「边距折叠」、「多栏自适应」、「高度塌陷」等问题,但是并不能说出解决问题的原理