CSS 中很重要的一环就是 BFC 块级格式化上下文,本文整理了 CSS BFC 的相关知识,建议沐浴更衣后食用。
在正式讲解BFC之前,先了解一下浏览器外边距重叠的问题。
外边距重叠
MDN:块的上外边距(margin-top)和下外边距(margin-bottom)有时合并(折叠)为单个边距,其大小为单个边距的最大值(或如果它们相等,则仅为其中一个),这种行为称为边距折叠。 注意:外边距重叠都是发生在块级元素中,设定 float 和 position=absolute 的元素不会产生外边距重叠行为。
有三种情况会形成外边距重叠:
- 同一层相邻元素之间:相邻的两个元素之间的外边距重叠。box1和box2的margin为200px
<style>
div {
width: 100px;
height: 100px;
background-color: pink;
}
.box1{
margin-bottom: 100px;
}
.box2{
margin-top: 200px;
}
</style>
<div class="box1"></div>
<div class="box2"></div>
复制代码
- **没有内容将父元素和后代元素分开:**如果没有边框 border,内边距 padding,行内内容,也没有创建块级格式上下文就会出现父块元素和其内后代块元素外边界重叠,重叠部分最终会溢出到父级块元素外面。如下:wrapper 有 100px 的上外边距,而 box 和 wrapper 之间是没有 100px 的上外边距。
<style>
.wrapper {
width: 200px;
height: 200px;
background-color: pink;
}
.box{
width: 100px;
height: 100px;
margin-top: 100px;
background-color: powderblue;
}
</style>
<div class="wrapper">
<div class="box"></div>
</div>
复制代码
- **空的块级元素:**如下示例,内容1 和 内容2 之间有200px的距离。
<style>
div {
margin-top: 100px;
margin-bottom: 200px;
}
</style>
<p>内容1</p>
<div></div>
<p>内容2</p>
复制代码
格式化上下文
行内格式化上下文(Inline formatting context)
各行内框(inline boxes)一个接一个地排列,其排列顺序根据书写模式的设置来决定:
- 对于水平书写模式,各个框从左边开始水平地排列
- 对于垂直书写模式,各个框从顶部开始水平地排列
.horizontal {
writing-mode: horizontal-tb; // 从左开始
}
.vertical {
writing-mode: vertical-rl; // 从上开始
}
复制代码
块格式化上下文
块格式化上下文(Block Formatting Context,BFC) 是 Web 页面的可视 CSS 渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。形成独立的渲染区域,内部元素的渲染不会影响外界。
总结来说具有 BFC 特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC 具有普通容器所没有的一些特性。
触发BFC的条件「常见」
- 根元素()
- 浮动元素(元素的 float 不是 none)
- 绝对定位元素(元素的 position 为 absolute 或 fixed)
- 行内块元素(元素的 display 为 inline-block、table-cells、flex)
- overflow 值不为 visible 的块元素 (hidden、auto、scroll)
BFC的特性
- BFC是独立容器,容器内部元素不会影响容器外部元素。
- 计算BFC的高度时,浮动元素也参与计算。
- BFC的区域不会与float的元素区域重叠。
注意:很多博客都会将属于同一个BFC的两个相邻盒子的margin会发生重叠
认为是BFC的特性,不是!不是!没有触发 BFC 也是如此排列的。BFC 可以解决这种重叠,但对于margin重叠,我们通常不解决,合理利用就好了。
BFC的常用案例:
1、解决 margin 重叠
- 相邻子元素的重叠
内部的盒子会在垂直方向上一个接一个的放置,垂直方向上的距离由margin决定。BFC可以避免margin折叠,例子:
<style>
.wrapper{
border: 1px solid black;
}
.box {
width: 200px;
height: 200px;
background-color: #999;
}
.box1 {
margin-bottom: 100px;
}
.box2 {
margin-top: 200px;
}
</style>
<div class="wrapper">
<div class="box1 box"></div>
<div class="box2 box"></div>
</div>
复制代码
如下图,在普通文档流中,两个相邻容器的上下margin会重叠,并且取其最大的margin。
如果让其中一个盒子处于独立的BFC中,就不会重叠。如下图
<style>
.wrapper{
border: 1px solid black;
}
.wrapper2{
overflow: hidden;
}
.box {
width: 200px;
height: 200px;
background-color: #999;
}
.box1 {
margin-bottom: 100px;
}
.box2 {
margin-top: 200px;
}
</style>
<div class="wrapper">
<div class="wrapper2">
<div class="box1 box"></div>
</div>
<div class="box2 box"></div>
</div>
复制代码
- 父子元素的margin重叠
<style>
.wrapper{
width: 200px;
height: 200px;
background: powderblue;
overflow: hidden;
}
.box{
width: 100px;
height: 100px;
margin-top: 100px;
background: pink;
}
</style>
<div class="wrapper">
<div class="box"></div>
</div>
复制代码
下图1为没有触发BFC,box的margin-top溢出到父元素。下图2为触发了BFC,内部的元素不会影响外部。
2、撑开float父元素高度
计算BFC的高度时,浮动元素也参与计算。可以用此撑开父元素。
<style>
.wrapper{
border: 1px solid black;
}
.box{
width: 100px;
height: 100px;
background: pink;
float: left;
}
</style>
<div class="wrapper">
<div class="box"></div>
</div>
复制代码
因为浮动会脱离普通流,形成浮动流,所以父级高度不会被子元素撑开。如下图
当触发BFC时,float元素会计入高度的计算中。
<style>
.wrapper{
border: 1px solid black;
overflow: hidden;
}
.box{
width: 100px;
height: 100px;
background: pink;
float: left;
}
</style>
<div class="wrapper">
<div class="box"></div>
</div>
复制代码
3、可以清除浮动
BFC的区域不会与float的元素区域重叠。所以可以用来清除浮动
<style>
.box1{
width: 100px;
height: 100px;
background: pink;
float: left;
}
.box2{
width: 200px;
height: 200px;
background: powderblue;
}
</style>
<div class="box1"></div>
<div class="box2"></div>
复制代码
结果如下图,可以看到,box2会和box1重叠出现。
当我们触发BFC之后,可以看到下图,并不会与float重叠
<style>
.box1{
width: 100px;
height: 100px;
background: pink;
float: left;
}
.box2{
width: 200px;
height: 200px;
background: powderblue;
overflow: hidden;
}
</style>
<div class="box1"></div>
<div class="box2"></div>
复制代码
4、实现两栏、三栏布局
- BFC的区域不会与float的元素区域重叠。这个特性也可以实现两栏布局。给固定栏设置固定宽度,给不固定栏开启BFC。
<style>
.left{
width: 100px;
height: 100px;
background: pink;
float: left;
}
.right{
height: 100px;
background: powderblue;
overflow: hidden;
}
</style>
<div class="left"></div>
<div class="right"></div>
复制代码
- 三栏布局同理,左右固定,中间不固定。需要注意的是,center中间部分的div要放在left、right后面。
<style>
.left {
width: 100px;
height: 100px;
float: left;
background: #ffc0cb;
}
.right {
width: 100px;
height: 100px;
float: right;
background: #ffc0cb;
}
.center{
height: 100px;
background: powderblue;
overflow: hidden;
}
</style>
<div class="left"></div>
<div class="right"></div>
<div class="center"></div>
复制代码
5、防止 float 文字环绕。
没啥卵用,但是这是一个用处。
<style>
.left {
width: 100px;
height: 100px;
background: #ffc0cb;
float: left;
}
p{
width: 200px;
background: powderblue;
overflow: hidden;
}
</style>
<div class="left"></div>
<p>
你好世界你好世界你好世界你好世界你好世界你好世界你好世界你好世界你好世界你好世界你好世界
</p>
复制代码
我们经常用 float 来实现文字环绕的报纸效果,但如果你不想环绕......就可以触发 BFC 实现
希望对大家有用,记得点赞关注哦~