一、什么是BFC?
借鉴了文章 👉 面试官:谈谈你对BFC的理解?
我们在页面布局的时候,经常出现以下情况:
这个元素高度怎么没了?
这两栏布局怎么没法自适应?
这两个元素的间距怎么有点奇怪的样子?
…
原因是元素之间相互的影响,导致了意料之外的情况,这里就涉及到了 BFC 概念 :
BFC(Block Formatting Context)
,即块级格式化上下文,它是页面中的一块渲染区域,并且有一套属于自己的渲染规则(前三条规则仅针对于非BFC元素):
- 内部的盒子会在垂直方向上一个接一个的放置;
- 对于同一个BFC下的两个上下相邻盒子的 上下外边距 (margin) 会发生重叠;
- 每个元素的左外边距与包含块的左边界相接触( 即BFC中子元素不会超出他的包含块 ),即使浮动元素也是如此;
- BFC的区域不会与浮动的元素区域重叠;
- 计算BFC的高度时,浮动子元素也参与计算;
BFC
的目的是形成一个相对于外界完全独立的空间,让内部的子元素不会影响到外部的元素,反之亦然
下面我们来直观的演示一下BFC的渲染规则:
-
内部的盒子会在垂直方向上一个接一个的放置
一个简单的代码示例:
<style> body { width: 300px; } .BFC { overflow: hidden; } .aside, .aside2 { width: 100px; height: 150px; background: #f66; } .aside2 { background-color: rgb(16, 171, 176); } .main { height: 200px; background: #fcc; } </style> <body> <div class="BFC"> <div class="aside"></div> <div class="aside2"></div> <div class="main"></div> </div> </body>
效果图,BFC里面的元素依次垂直排列:
-
对于同一个BFC下的两个上下相邻盒子的 上下外边距 (margin) 会发生重叠
我们在上一个代码的基础上,为
aside
和aside2
分别增加了上边距和下边距:.aside { margin-bottom: 30px; } .aside2 { margin-top: 30px; }
理想效果应该是
aside
和aside2
之间的间距为 60px,下面是实际效果图:下面这张图是
aside
的下外边距:下面这张图是
aside2
的上外边距:
可以清楚地看到,他们的外边距发生了重叠,且重叠后的高度为30px那看官可能又会有一个疑问:如果一个外边距是 40px ,另一个外边距是 30px 呢?
答案是:外边距重叠后的总外边距,以外边距更大的一方为准; 看官可以自己实验一下;
为什么重叠现象只会发生在上下相邻的盒子,并且只有上外边距和下外边距会发生重叠?
①因为 display:block;
不会触发BFC,所以只有块状元素会发生外边距重叠现象,而行内元素和行内块元素均会触发BFC!
②块状元素默认独占一行,所以只会出现上下相邻的现象,如果通过浮动让其排列在同一行,则又会触发BFC!
-
每个元素的左外边距与包含块的左边界相接触( 即BFC中子元素不会超出他的包含块 ),即使浮动元素也是如此
下面的代码在上述代码的基础上为
aside
和aside2
添加了左浮动,完整代码示例:<style> body { width: 300px; } .BFC { overflow: hidden; } .aside, .aside2 { float: left; width: 100px; height: 150px; background: #f66; } .aside2 { background-color: rgb(16, 171, 176); } .main { height: 200px; background: #fcc; } </style> <body> <div class="BFC"> <div class="aside"></div> <div class="aside2"></div> <div class="main"></div> </div> </body>
实际效果图:
由于float元素脱离了标准流,所以
main
盒子和浮动元素的区域发生了重叠,但它们都没有超出它们的包含块;
-
BFC的区域不会与浮动的元素区域重叠
这一渲染规则刚好可以解决上面的问题,只需要为
main
盒子添加overflow:hidden;
使其成为BFC元素就可以解决与浮动元素的区域重叠的问题:.main { overflow: hidden; height: 200px; background: #fcc; }
效果图:
-
计算BFC的高度时,浮动子元素也参与计算
非常的简单,即清除浮动造成的影响,代码示例:
<style> .par { width: 300px; border: 5px solid #fcc; } .child { float: left; width:100px; height: 100px; border: 5px solid #f66; } </style> <body> <div class="par"> <div class="child"></div> <div class="child"></div> </div> </body>
页面显示如下:
最外面的盒子 par 没有高度,两个浮动的子元素没有参与高度计算要想让par获得高度,只要让它触发BFC就好了
.par { overflow: hidden; }
效果如下:
二、BFC的触发条件:
触发BFC的条件包含不限于:
- 根元素,即
<html>
元素 - 浮动元素:float值 不为 none
- overflow值不为 visible,
为 auto、scroll、hidden
- display的值为
inline-block、 inltable-cell、 table-caption、 table、 inline-table、 flex、 inline-flex、 grid、 inline-grid
- position的值为 absolute 或 fixed
三、BFC的应用场景:
利用 BFC
的渲染规则的特性,我们将 BFC
应用在以下场景:
1. 防止margin重叠(塌陷)
<style>
p {
margin: 100px;
width: 200px;
color: #f55;
background: #fcc;
line-height: 100px;
text-align:center;
}
</style>
<body>
<p>Haha</p >
<p>Hehe</p >
</body>
页面显示如下:
两个 p 元素之间的距离为100px,发生了margin重叠(塌陷),且重叠后的总外边距以最大的为准,如果第一个 p 的 margin 为 80px 的话,两个 p 之间的距离还是100;
那么我们可以在 p 外面包裹一层容器,并触发这个容器生成一个BFC,那么两个 p 就不属于同一个BFC,则不会出现 margin 重叠:
<style>
.wrap {
overflow: hidden;// 新的BFC
}
p {
margin: 100px;
width: 200px;
color: #f55;
background: #fcc;
line-height: 100px;
text-align:center;
}
</style>
<body>
<p>Haha</p >
<div class="wrap">
<p>Hehe</p >
</div>
</body>
2. 清除内部浮动影响
<style>
.par {
width: 300px;
border: 5px solid #fcc;
}
.child {
float: left;
width:100px;
height: 100px;
border: 5px solid #f66;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
页面显示如下:
最外面的盒子 par 没有高度,两个浮动的子元素没有参与高度计算
要想让par获得高度,只要让它触发BFC就好了
BFC在计算高度时,浮动元素也会参与
.par {
overflow: hidden;
}
效果如下:
3. 自适应多栏布局(或者说解决浮动元素覆盖盒子区域的问题)
这里的举例为两栏布局
<style>
body {
width: 300px;
}
.aside,
.aside2 {
float: left;
width: 100px;
height: 150px;
background: #f66;
}
.aside2 {
background-color: rgb(16, 171, 176);
}
.main {
height: 200px;
background: #fcc;
}
</style>
<body>
<div class="aside"></div>
<div class="aside2"></div>
<div class="main"></div>
</body>
效果图如下:
前面讲到,BFC 中的每个元素的左外边距与包含块的左边界相接触,并且由于 .aside
和 .aside2
为浮动元素,所以 main
区域与 .aside2
区域发生了重叠
但是 BFC 的区域不会与浮动盒子重叠
所以我们可以通过触发 main 生成 一个新的BFC, 以此适应两栏布局
.main {
overflow: hidden;
}
这时候,新的 BFC 不会与浮动的 .aside 元素重叠。
因此 main 会根据包含块的宽度,和 .aside 的宽度,自动变窄
效果如下:
可以看到,上面几个案例都体现了BFC实际就是页面一个独立的容器,里面的子元素不影响外面的元素,外面的元素也不会影响到里面的子元素;