一、什么是BFC?
BFC即Block Formatting Context,直译为“块级格式化上下文”,它是W3C CSS2.1规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其他元素的关系和相互作用。它其实就是一个看不见摸不着的区域,不管BFC元素内部子元素怎么变化,都不会影响外部的元素。常用来解决如清除浮动、防止margin重叠等问题。
二、BFC布局规则
- 内部的Box会在垂直方向,一个接一个地放置;
- Box垂直方向的距离由margin决定,属于同一个BFC的两个相邻Box的margin会发生重叠;
- 每个元素的margin-box的左边,与包含border box的左边相接触(对于从左往右的格式化,否则相反),即使存在浮动也是如此;
- BFC的区域不会与float box重叠;
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然;
- 计算BFC的高度时,浮动元素也参与计算。
三、怎样触发BFC?
- 根元素(html);
- float属性不为none;
- position为absolute或fixed;
- display为inline-block, table-cell,table-caption,flex,inline-flex;
- overflow不为visible
四、BFC的作用与原理
1. 自适应两栏布局
代码:
<style>
body {
width: 300px;
position: relative;
}
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
background: #fcc;
}
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>
页面:
根据BFC布局规则第三条:
“每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。”
因此,虽然存在浮动的元素aside,但main的左边依然会与包含块的左边相接触。
根据BFC布局规则第四条:
“BFC的区域不会与float box重叠。”
我们可以通过通过触发main生成BFC,来实现自适应两栏布局。
.main {
overflow:hidden;
}
当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。效果如下:
2. 清除内部浮动
代码:
<style>
.par {
border: 5px solid #fcc;
width: 300px;
}
.child {
border: 5px solid #f66;
width:100px;
height: 100px;
float: left;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
页面:
父元素内部的子元素浮动时,父元素的高度会发生塌陷,这是一个很常见的问题。
根据BFC布局规则第六条:
“计算BFC的高度时,浮动元素也要参与计算。”
为达到清除内部浮动,可以通过触发父元素par生成BFC,在计算par高度时,par内部的浮动元素child也会参与计算。
代码:
.par {
overflow: hidden;
}
效果如下:
父元素高度被重新撑开。
3. 防止垂直margin重叠
在CSS中,相邻的两个盒子(可能是兄弟关系也可能是祖先关系)的外边距可能会发生重叠,需要注意的是,重叠只发生在垂直方向,水平方向不会发生。重叠的结果是:
- 两个相邻的外边距都是正数时,重叠结果是它们两者之间的较大值;
- 两个相邻外边距都是负数时,重叠结果是两者绝对值的较大值;
- 两个外边距一正一负时,重叠结果是两者的相加的和。
代码:
<style>
div {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<div>Haha</div>
<div>Hehe</div>
</body>
页面效果:
两个div之间的距离为100px,发生了margin重叠。根据BFC布局规则第二条:
“Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。”
对于这种两个兄弟元素垂直方向的margin重叠,最简单的解决方法就是不要同时既设置一个元素的margin-bottom又设置另一个元素的margin-top,将它们之间的margin值统一设置到一个元素的margin-top或margin-bottom上。
当然这里讲到BFC,自然要提用BFC的方法来解决。我们可以通过在其中一个div外面包裹一层容器,并触发该容器生成一个BFC,那么这两个div就不属于同一个BFC,自然就不会发生margin重叠了。
代码:
<style>
.one {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
.wrap {
overflow: hidden;
}
</style>
<body>
<div class="one">Haha</div>
<div class="wrap">
<div class="one">Hehe</div>
</div>
</body>
页面效果:
还有一种情况是嵌套关系的Box。
代码:
<style>
body {
font-family: 'Microsoft Yahei';
}
.par {
background: #f66;
width: 300px;
height: 200px;
}
.child {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin-top: 50px;
}
</style>
<body>
<div class="par">
<div class="child">child</div>
</div>
</body>
页面效果:
我们希望的是里面的盒子与包裹它的父盒子之间有一定的间距,但是很不幸的是外层div也跟着一起移下来了,它们俩还是紧紧地贴在一起。
根据BFC规则第五条:
“BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之亦然。”
这种情况同样可以通过触发父元素产生一个BFC来解决,轻松达到我们想要的结果。
代码:
<style>
body {
font-family: 'Microsoft Yahei';
}
.par {
background: #f66;
width: 300px;
height: 200px;
overflow: hidden;
}
.child {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin-top: 50px;
}
</style>
<body>
<div class="par">
<div class="child">child</div>
</div>
</body>
页面效果:
当然我们还可以通过直接设置父盒子的padding值来解决。同时我们还可以通过给父元素设置一个border,也可以达到我们想要的效果。
五、总结
其实以上的几个例子都体现了BFC布局的第五条规则,即:
“BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之亦然。”
因为BFC内部的元素和外部的元素绝对不会互相影响,因此,当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是同样的道理。
参考链接:
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://www.zhangxinxu.com/wordpress/2015/02/css-deep-understand-flow-bfc-column-two-auto-layout/
http://www.w3cplus.com/css/understanding-bfc-and-margin-collapse.html