1. 块级格式化上下文(BFC)
它是一块独立的渲染区域,有一套自己的渲染规则。规定该区域内的元素布局与外部不会相互影响。
先来说一下常规流块盒:
- 常规流块盒在水平方向上,必须盛满包含块
- 常规流块盒在包含块的垂直方向上依次摆放
- 常规流块盒若外边距无缝相邻,则进行外边距合并
- 常规流块盒的自动高度和摆放位置,无视浮动元素
BFC 渲染区域:
这个区域由某个 HTML 元素创建,以下元素会在其内部创建 BFC 区域:
- 根元素:html 元素创建的 BFC 区域,覆盖了网页中所有的元素
- 浮动和绝对定位元素
- overflow 不等于 visible 的块盒
不同的BFC 区域,它们进行渲染时互不干扰。
创建 BFC 的元素,隔绝了它内部和外部的联系,内部的渲染不会影响到外部。
具体规则:
- 创建 BFC 的元素,它的自动高度需要计算浮动元素
- 创建 BFC 的元素,它的边框盒不会与浮动元素重叠
- 创建 BFC 的元素,不会和它的子元素进行外边距的合并
- 内部的盒子会在垂直方向上一个接一个的放置
- 盒子垂直方向上的距离由 margin 决定,属于同一个 bfc 的两个相邻的 盒子的margin 会发生重叠
- 每个盒子的左外边框紧挨着包含块的左边框,即使浮动元素也是如此
- bfc 的区域不会与浮动 盒子重叠
- 计算 bfc 的高度时,浮动元素也参与计算
唉??等等。。body 里面的盒子不就是这样的规则吗?emmm… 对!因为标准流里面的 body 元素就是一个天然的 bfc。
1.1 创建 BFC 的元素,它的自动高度需要计算浮动元素
小例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
>
<title>Document</title>
<style>
.container {
background: pink;
}
.item {
float: left;
width: 200px;
height: 200px;
margin: 20px;
background: blue;
}
</style>
</head>
<body>
<div class="container">
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
<div class="item"></div>
</div>
</body>
</html>
发现背景颜色没有了,因为高度坍塌,父盒子的高度为 0。
清除浮动:
.clearfix::after {
content: '';
display: block;
clear: both;
}
但是现在,我们知道了创建 BFC 的元素,它的自动高度需要计算浮动元素。
所以,可以给父元素绝对定位或者给一个浮动,这样它的内部就会创建 BFC。也可以解决高度塌陷问题。
.container {
background: pink;
/* position: absolute; */
float: left;
}
但是这两种做法都不好,都影响到其他布局。
所以我们可以再换一种做法:
overflow: hidden;
将父元素设置为 overflow 不等于 visible 的块盒(其中使用 hidden 副作用最小,没有多余的滚动条)。
综上所述,清除浮动最好的方式还是 clearfix 清除浮动,因为它的唯一作用就是用来解决高度坍塌。
此外,该做法还可以让让浮动内容和周围的内容等高:创建一个会包含这个浮动的BFC,通常的做法是设置父元素 overflow: auto 或者设置其他的非默认的 overflow: visible 的值。
补充:
还有一种影响较小的方法,通过伪类清除浮动。
1.2 创建 BFC 的元素,它的边框盒不会与浮动元素重叠
小例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
>
<title>Document</title>
<style>
.float {
float: left;
width: 100px;
height: 100px;
margin: 20px;
background: pink;
}
.container {
width: 400px;
height: 200px;
background: yellowgreen;
}
</style>
</head>
<body>
<div class="float"></div>
<div class="container"></div>
</body>
</html>
给 container 创建 BFC:
.container {
width: 400px;
height: 200px;
background: yellowgreen;
/* 创建 BFC */
overflow: hidden;
}
此时 container 盒子的 margin-left 是相对于页面的 body 的最左边缘。
如果要调整元素的位置,可以调整 float 元素的 margin-right。
1.3 创建 BFC 的元素,不会和它的子元素进行外边距的合并
小例子:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
>
<title>Document</title>
<style>
.container {
background: pink;
height: 500px;
margin-top: 30px;
/* overflow: hidden; */
}
.child {
height: 100px;
margin: 50px;
background: yellowgreen;
}
</style>
</head>
<body>
<div class="container">
<div class="child"></div>
</div>
</body>
</html>
给父元素加上创建 BFC:
overflow:hidden;
上边距并没有合并。
2. 总结
可以通俗的理解为 BFC 就是一个功能,创建了 BFC 就相当于开启了这个功能。
开启了BFC能解决什么问题:
- 元素开启 BFC 后,其子元素不会再产生 margin 塌陷问题。
- 元素开启 BFC 后,自己不会被其他浮动元素所覆盖。
- 元素开启 BFC 后,就算其子元素浮动,元素自身高度也不会塌陷。
如何开启 BFC:
- 根元素
- 浮动元素
- 绝对定位、固定定位的元素
- 行内块元素
- 表格单元格: table、thead、tbody、tfoot、th、td、tr、caption
- overflow 的值不为 visible 的块元素(相对来说影响小些)
- 伸缩项目(父元素 flex,自身开启 BFC)
- 多列容器(column-count)
- column-span为 all 的元素(即使该元素没有包裹在多列容器中)
- display 的值,设置为 flow-root,inline-block, table-cell , table-caption , flex, inline-flex 中的任何一个
float: left;
position: absolute;
display: inline-block;
display: table;
overflow: auto;
column-count: 1;
display: flow-root;
拓展:
IFC : 行内格式化上下文。也就是一块区域以行内元素的形式来格式化。
GFC :网格布局格式化上下文,将一块区域以grid 网格 的形式格式化
FFC : 弹性格式化上下文,将一块区域以弹性盒的形式来格式化
没有 KFC 喔 😋