块级格式化上下文(Block Formatting Context)是网页CSS视觉渲染的一部分,并用于决定块盒子的布局。在定位体系(Positioning Scheme)中它属于常规流(Normal Flow)。
浮动、绝对定位元素(position 为 absolute 或 fixed)、行内块元素 display:inline-block、表格单元格display:table-cell、表格标题 display:table-caption 以及 overflow 属性值不为 visible 的元素都将创建一个新的块级格式化上下文。
一个BFC就是一个HTML盒子,它至少满足以下条件之一:
- 根元素或其它包含它的元素;
- 浮动 (元素的float不为none);
- 绝对定位元素 (元素的position为absolute或fixed);
- 行内块inline-blocks(元素的 display: inline-block);
- 表格单元格(元素的display: table-cell,HTML表格单元格默认属性);
- overflow的值不为visible的元素;
- 弹性盒 flex boxes (元素的display: flex或inline-flex);
最常见的是: overflow:hidden、float:left/right、position:absolute。也就是说,每次看到这些属性的时候,就代表了该元素以及创建了一个BFC了。
在一个块级格式化上下文中,盒子在竖直方向一个接一个地放置,从包含块的顶部开始。两个兄弟盒之间的竖直距离由’margin’属性决定。同一个块格式化上下文中的相邻块级盒之间的竖直margin会合并,水平方向上margin不合并。
创建一个块级格式化上下文
一个BFC可以显式触发。如果我们想创建之,我们只需给它添加上面提到的任何一个CSS样式。
一个新的BFC可以通过给容器添加任意一个必要的CSS样式来创建,比如overflow: scroll,overflow: hidden,display: flex,float: left,或 display: table。尽管上述条件都可以创建BFC,但也会产生一些其他效果,如:
- display: table 可能引发响应性问题
- overflow: scroll 可能产生多余的滚动条
- float: left 将把元素移至左侧,并被其他元素环绕
- overflow: hidden 将裁切溢出元素
所以无论何时,当要创建一个BFC时,我们要基于需求选择最恰当的样式。
BFC中盒子的对齐
W3C规范中讲到:在BFC上下文中,每个盒子的左外侧紧贴包含块的左侧(从右到左的格式里,则为盒子右外侧紧贴包含块右侧),甚至有浮动也是如此(尽管盒子里的行盒子 Line Box 可能由于浮动而变窄),除非盒子创建了一个新的BFC(在这种情况下盒子本身可能由于浮动而变窄)。
BFC应用
清除浮动
在这以前,知道给父元素设置overflow:hidden可以清除子元素的浮动,但是不知道原理是什么。现在学习了BFC后,理解了其原理:当在父元素中设置overflow:hidden时就会触发BFC,所以他内部的元素就不会影响外面的布局,BFC就把浮动的子元素高度当做了自己内部的高度去处理溢出,所以外面看起来是清除了浮动。
Demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>清除浮动</title>
<style type="text/css">
.wrap{
padding: 5px;
border: 1px solid blue;
overflow: hidden;
}
.box{
width: 100px;
height: 100px;
background-color: red;
margin-bottom: 5px;
float: left;
}
</style>
</head>
<body>
<div class="wrap">
<div class="box">浮动div1</div>
<div class="box">浮动div2</div>
<div class="box">浮动div3</div>
</div>
</body>
</html>
消除margin合并
margin会产生合并(经测试只会发生上下margin的合并,左右的margin不会发生合并)的情况有2种:一种是兄弟元素之间,一种是父元素和子元素之间。
这里我举例说明下父元素和子元素之间margin合并的消除。
父元素和子元素产生margin合并的条件是:处于同一个块级格式上下文中,且两者之间没有padding,border和空隙。
当然我们可以通过给父元素和子元素增加border,padding的方法来消除,但是有时候我们可能不需要border和padding。所以还有另一种好的方法是可以给父元素设置新的块级格式上下文,加一个overflow:hidden。这样父元素就不会和子元素的margin发生重叠了。
Demo:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>消除margin合并</title>
<style type="text/css">
.wrap{
width: 200px;
height: 200px;
background-color: red;
margin: 10px;
/*可以通过给父元素和子元素同时设置border属性来消除marhin的合并*/
/*border: 1px solid #000;*/
overflow: hidden;
}
.box{
width: 100px;
height: 100px;
background-color: blue;
margin: 10px;
/*border: 1px solid #000;*/
}
</style>
</head>
<body>
<div class="wrap">
<div class="box">我是子元素</div>
</div>
</body>
</html>
小结
当我们在进行盒模型布局的时候,如果一个元素符合了成为BFC的条件,该元素将成为一个隔离的独立容器,内部元素会垂直的沿着其父元素的边框排列,和外部元素互不影响 。
推荐几篇不错的博文:
1.学习BFC
2.什么是BFC
3.前端精选文摘:BFC 神奇背后的原理