好奇BFC是什么?是页面布局的核心规则?🤡
引言
本次讨论将深入探讨BFC(Block Formatting Context,块级格式化上下文)的几条核心规则,根据具体例子解释它们的用法。
盒模型
在了解BFC之前,我们先来理解一下盒模型。
一个盒子是由content、padding、border、margin组成的。
有两种不同的盒模型:标准盒模型和怪异盒模型。
两种盒模型由CSS中的box-sizing属性来控制
- 标准盒模型(content-box) 标准盒模型就是默认的盒模型。标准盒模型,元素的宽度和高度仅包括内容区域,不包含内边距、边框和外边距,这些部分会额外增加元素的实际尺寸。
- 怪异盒模型(border-box) 怪异盒模型将宽度和高度应用到内容、内边距和边框的总和上。
在下面的代码中,我们将box1为默认状态,box2设置怪异盒模型,box3设置标准盒模型。宽高都设置为100px。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>一个盒子,自己的规则</title>
<style>
*{
margin: 0;
padding: 0;
}
/* 盒模型 + 块级 */
.box1,.box2,.box3 {
width: 100px;
height: 100px;
padding: 10px;
border: 1px solid red;
background-color: green;
}
.box2 {
/* border 以内盒子的大小 IE 怪异盒模型 */
box-sizing: border-box;
}
.box3 {
/* 默认值,标准盒模型 w h content大小 */
box-sizing: content-box;
}
</style>
</head>
<body>
<div class="box1"></div>
<div class="box2"></div>
<div class="box3"></div>
</body>
</html>
可以看到,box1和box3都是变成了122px122px,因为他们都是content-box,宽高为content的大小。而box2为border-box,是100px100px,它以border作为宽高
元素分类
根据元素默认的显示行为,可以将元素分为两大类:块级元素(Block-level Elements) 和 行内元素(Inline Elements) 。
- 块级元素独占一行,可以设置宽高,支持所有的外边距、内边距和边框属性。
- 行内元素与其他行内元素在同一行内流动显示,直到遇到块级元素或行宽不够时才会换行。只有水平方向的内边距和边框会对布局产生影响。
html
代码解读
复制代码
<!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>
* {
margin: 0;
padding: 0;
}
div {
width: 100px;
height: 100px;
border: 1px solid red;
padding: 10px 20px;
display: inline;
}
span {
width: 100px;
height: 100px;
display: block;
background-color: green;
}
</style>
</head>
<body>
<div>123</div>
<span>11</span><span>222</span>
</body>
</html>
行内元素设置的宽高并没有生效,并且设置的垂直方向的内边距和边框也没有对下面的块级元素产生影响。
BFC - 块级格式化上下文
什么是BFC?
BFC(Block Formatting Context,块级格式化上下文) 是Web页面中一个独立的渲染区域。在这个区域内,元素按照特定规则进行布局,并且该区域内的元素不会受到外部元素的影响,也不会影响外部元素的布局。BFC在潜移默化的影响着页面的布局。
触发BFC创建的完整方式
-
文档根元素
<html>元素自动创建最顶层的BFC -
浮动元素 CSS设置:
float: left | right | inline-start | inline-end -
绝对定位元素 CSS设置:
position: absolute | fixed -
行内块元素 CSS设置:
display: inline-block -
表格相关元素
display: table-cell(表格单元格)display: table-caption(表格标题)display: table | inline-table(匿名表格元素)
-
overflow属性 CSS设置:
overflow: hidden | auto | scroll | overlay(非visible值) -
弹性容器 CSS设置:
display: flex | inline-flex(同时创建FFC) -
网格容器 CSS设置:
display: grid | inline-grid(同时创建GFC) -
多列容器
column-count: <number>column-width: <length>(不能为auto值)
- 其他特殊情况
contain: layout | content | strictdisplay: flow-root(最纯净的BFC创建方式)
注意事项
- 某些属性会同时创建不同类型的格式上下文:
- Flex布局会创建FFC
- Grid布局会创建GFC
- 多列布局会创建多列格式上下文
-
display: flow-root是专门用于创建BFC的属性值,不会产生其他副作用 -
实际开发中最常用的BFC创建方式:
.bfc-container {
overflow: hidden; /* 最常用 */
display: flow-root; /* 最规范 */
display: flex; /* 同时创建FFC */
position: absolute; /* 改变定位 */
}
-
BFC创建具有"开关"特性,一旦触发就会影响所有子元素
-
某些CSS属性组合可能意外触发BFC,需要注意检查
BFC 核心布局规则详解
我在这里直接列出了BFC的规则,在下面的代码中将解释这些规则。
一、垂直流排列原则(block level box 垂直方向,一个接一个的放置)
在同一个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>
* {
margin: 0;
padding: 0;
}
.div1,.div2{
width: 100px;
height: 100px;
}
.div1 {
background-color: red;
}
.div2 {
background-color: green;
}
</style>
</head>
<body>
<div class="div1"></div>
<div class="div2"></div>
</body>
</html>
二、外边距折叠机制(盒子垂直方向的距离由margin决定,同一个BFC相邻盒子margin会重叠)
当同一BFC内的相邻块级元素设置垂直方向的外边距时,会发生外边距合并现象。两个正值外边距会取较大值,正负值会相抵消,两个负值则取绝对值较大的那个。这是BFC布局中最常见的"外边距塌陷"现象的来源。
第二条原则。我们给上面的盒子设置下外边框50px,下面的盒子设置上外边框30px。可以看到,最后得到的结果中,两个盒子之间并不是80px,而是50px。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BFC</title>
<style>
*{
margin: 0;
padding: 0;
}
.box {
width: 200px;
height: 200px;
background-color: lightblue;
border: 1px solid #000;
}
.box1 {
margin-bottom: 50px;
}
.box2 {
margin-top: 30px;
}
</style>
</head>
<body>
<div class="box box1">Box1</div>
<div class="box box2">Box2</div>
</body>
</html>
因为它们处在同一个BFC之中,外边框重叠了。 有三种情况:
- 如果两个都是正值,实际距离取较大值
- 如果一个正一个负,取差值
- 如果两个都为负,取绝对值最大的 所以为了实现想要的效果,我们要把它们放在不同的BFC中,创建一个新的BFC就能够让它们之间的间距为80px了。
<div class="box box1">Box1</div>
<!-- 开启新的格式化上下文 -->
<div style="overflow:hidden;"></div>
<div class="box box2">Box2</div>
三、边界对齐原则(每个元素的margin左边,与包含块(父元素)border的左边相接触,即使存在浮动也会忽略浮)
BFC内的每个元素,其左外边距边界始终与包含块的左边框边界保持对齐。这个规则即使遇到浮动元素也不会改变,导致浮动元素可能会覆盖后续内容。只有创建新的BFC才能打破这种对齐关系。
第三条原则。还是拿上面的例子,给Box1和Box2添加左外边框。可以看到,margin左边紧贴父元素的border。(例子中已经清除了默认的外边框和内边框)
四、浮动隔离特性(BFC 区域不会与float box 重叠)
BFC区域与浮动元素之间存在天然的排斥关系。一个建立了BFC的盒子会自动避开浮动元素所在的区域,形成内容环绕或者自适应布局的效果。这个特性常被用来实现图文混排等复杂布局。
在我们使用浮动后,元素将会脱离文档流。 没加BFC之前。在同一个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>
*{
margin: 0;
padding: 0;
}
.container {
border: 2px solid #000;
padding: 10px;
overflow: hidden;
}
.float-left {
float: left; /* Formatting context */
width: 150px;
height: 100px;
background-color: lightblue;
margin: 10px;
}
.margin-box {
width: 200px;
height: 100px;
background-color: lightgreen;
margin: 20px 0 20px 50px;
}
</style>
</head>
<body>
<div class="container">
<div class="float-left">这是一个左浮动的元素</div>
<div class="margin-box">这是有左侧外边距的盒子这是有左侧外边距的盒子这是有左侧外边距的盒子</div>
</div>
</body>
</html>
添加BFC之后,就不会重叠了。
.bfc-box {
width: 300px;
height: 100px;
background-color: lightgreen;
overflow: hidden;
/* 创建 BFC */
}
在这里使用 overflow: hidden;创建BFC,这也是常用的清除浮动的方法。
五、独立渲染空间(独立渲染区域,不受外界影响(内部也不受外部影响))
BFC创建了一个完全独立的布局环境,其内部元素的排列不会受到外部布局的影响,同时也不会影响到外部元素的布局。这种隔离特性使得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 {
border: 2px solid black;
padding: 10px;
}
.float-box {
float: left;
width: 150px;
height: 100px;
background-color: lightblue;
margin: 10px;
}
.bfc-box {
width: 300px;
height: auto;
background-color: lightgreen;
overflow: auto; /*创建 BFC 切换*/
padding: 10px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<div class="container">
<div class="float-box">这是一个左浮动的盒子</div>
<div class="bfc-box">
<p>这是创建了 BFC 的盒子内部的内容。</p>
<p>注意,这个内容不会被外部的浮动元素影响。</p>
</div>
</div>
</body>
</html>
六、浮动包含规则(计算BFC的高度时,浮动元素也参与计算)
普通容器在计算高度时会忽略浮动元素,导致"高度塌陷"。而BFC容器在计算高度时,会将内部所有浮动元素的高度也纳入计算范围,这个特性使得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>
/* 而用 BFC 清除浮动的原理就是:计算 BFC 的高度时,浮动元素也参与计算。只要触发父元素的 BFC 即可。 */
.parent {
background-color: red;
overflow: hidden;
}
.child {
float: left;
height: 200px;
width: 200px;
background-color: green;
}
</style>
</head>
<body>
<div class="parent">
<div class="child"></div>
</div>
</body>
</html>
如果没有设置BFC清除浮动将会是这样,父元素塌陷。
创建BFC之后,浮动元素也参与父元素的高度计算,把父元素撑起来了。
结语
综上所述,理解BFC及其工作机制对于掌握CSS布局原理和解决复杂的页面布局问题至关重要。BFC对于清除浮动和解决某些布局问题非常有用。通过合理地创建和利用BFC,开发者可以更精确地控制网页元素的排列和外观,避免不必要的样式冲突,从而构建更加稳健和高效的Web页面。
这就是BFC的全部内容了。时刻牢记BFC的几个规则。