学习HTML的时候遇到过这种情况:
两个块级box垂直方向相邻,如果设置它们的上下margin,就会发生重叠(margin塌陷)现象。
当时也没有想太多,只知道有这种情况,在使用的时候会尽量设置单个margin或者设置padding值,来避免出现重叠现象,但闲下来时,我仔细想了下这个问题,然后查询了一些资料,结果引出来一个东西 BFC。
BFC
什么是BFC?
要了解什么是BFC,就要涉及一些CSS布局的一些基本概念,其中块级盒的概念要清楚。
盒模型
在W3C规定里,完整的盒模型为:
- content:内容(主体)
- padding:内边距
- border:边框
- margin:外边距
每个块级元素都会自动生成一个块级盒block-level box,每个块级盒的盒模型结构都如上图盒模型一样。
其中,margin、padding、border、content分别定义了元素的四种边,每种类型的边定义了一种盒子,分别是margin box、padding box、border box 、content box。而控制块级盒之间的垂直间距的就是margin box。
我们对块级元素布局的描述为:
普通流中的块元素独占一行,然后从上往下一个接一个的排布,相邻元素间会有外边距折叠
为什么会是这种布局呢?原因就是BFC的存在
BFC定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
BFC布局规则(重点)
- 内部的Box会在垂直方向,一个接一个地放置。
- Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
- 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
- BFC的区域不会与float box重叠。
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
- 计算BFC的高度时,浮动元素也参与计算
触发(创建)BFC
- float的值不为none
- overflow的值为auto、scroll或hidden。
- display的值为inline-block, table-cell, table-caption, flex, inline-flex中的任何一个。
- position的值不为relative和static(可以为absolute或fixed)
BFC功能和作用
1. 自适应左右两栏布局
代码:
<style>
html,body{
width: 100%;
height: 100%;
}
.box1{
width: 180px;
height: 300px;
background-color: purple;
float: left;
}
.box2{
height: 100%;
background-color: yellow;
}
</style>
<body>
<div class="box1"></div>
<div class="box2"></div>
</body>
显示效果:
根据BFC布局规则:
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
因此,即时存在浮动元素box1,但box2的左边依然紧贴父元素左边界。
如何实现左右两栏分布?
根据BFC布局规则:
BFC的区域不会与float box重叠
可以设置box2为BFC,触发BFC效果,实现自适应两栏布局。
.box2{
height: 100%;
background-color: yellow;
overflow: hidden;
}
当触发box2生成BFC后,这个新的BFC就不会与浮动的box1重叠。因此box2会根据包含块(父元素)的宽度,和box1的宽度,自动变窄(自适应)。效果如下:
清除内部浮动
代码:
<style>
html,body{
width: 100%;
height: 100%;
}
.father{
width: 200px;
border:8px solid #d02c38;
}
.son{
width: 80px;
height: 80px;
border:5px solid #666666;
display: inline-block;
float: left;
}
</style>
<body>
<div class="father">
<div class="son"></div>
<div class="son"></div>
</div>
</body>
页面显示为:
father盒子中的son盒子全部为浮动后,内容无法撑起父盒子的高度,所以father盒子显示为一条宽度为16px的实线,想撑起父盒子的高度,就需要清除浮动带来的影响。
根据BFC规则:
计算BFC的高度时,浮动元素也参与计算
因此,father元素触发BFC,那么father元素计算高度的时候,会把son元素的高度也计算进去,相当于给father设置了高度,达到清除浮动的效果。
防止垂直重叠
在文章开头就说到,相邻两个块级元素的上下margin值会发生重叠现象。现在可以通过BFC来解决这个问题。
代码:
<style>
html,body{
width: 100%;
height: 100%;
}
.box1{
width: 100px;
height: 100px;
background-color: red;
margin-bottom: 50px;
}
.box2{
width: 100px;
height: 100px;
background-color: blue;
margin-top: 50px;
}
</style>
<body>
<div class="box1">box1</div>
<div class="box2">box2</div>
</body>
效果显示:两个盒子之间的距离设置上下各50px,按我们理解的来算应该是100px,但实际上是50px,外边距发生了重叠。
根据BFC规则:
Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
我们可以把这两个盒子设为不同的BFC,就能避免重叠。实际是给下面的盒子box2设置属性:
.box2{
width: 100px;
height: 100px;
background-color: blue;
margin-top: 50px;
display: inline-block;
/*overflow: hidden;*//在此处无效
}
效果为:
BFC的这些作用,都体现了BFC的最大的规则属性:
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
因为BFC内部的元素和外部的元素绝对不会互相影响,因此, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠,也是这样的一个道理。