Android开发人员一次搞懂前端BFC原理

什么是BFC

BFC全称是Block Formatting Context,即块格式化上下文。它是CSS2.1规范定义的,关于CSS渲染定位的一个概念。

在介绍清楚BFC之前,我们先简单回顾一下CSS中的盒模型:盒模型包括内容(Content)、Padding、边框(Border)和Margin 。

而块级格式化上下文(BFC)是页面中一个相对独立的模块,它定义了它内部的块级盒子(块级元素的盒子模型)如何排布和布局。html的根元素<html></html>标签就会产生一个BFC区域。

BFC规则

1、内部的块级盒子会在垂直方向,一个接一个地放置。

2、块级盒子垂直方向的距离由margin决定。属于同一个BFC的两个相邻块级盒子的margin会发生重叠。

3、每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。

4、BFC的区域不会与float box重叠。

5、BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。

6、计算BFC的高度时,浮动元素也参与计算。

创建新的BFC

根元素或其它包含它的元素;

浮动(元素的float不为none);

绝对定位元素(元素的position为absolute或fixed);

行内块inline-blocks(元素的display: inline-block);

表格单元格(元素的display: table-cell,HTML表格单元格默认属性);

overflow的值不为visible的元素;

弹性盒 flex boxes(元素的display: flex或inline-flex);

BFC的区域

1<div id="div0" class="main BFC">
2    <div id="div1" class="div1 margin-100px">元素1</div>
3    <div id="div2" class="div2 margin-100px">元素2</div>
4    <div id="div3"class="div3 margin-100px BFC">
5            <div id="div5" class="child">子元素1</div>
6            <div id="div6" class="child">子元素2</div>
7    </div>
8</div>

BFC区域包含创建BFC元素的所有子元素,但不包括又创建BFC元素下面的所有子元素。

看上面这段代码,id=div0的元素创建了一个BFC区域,该元素下面的id为div1div2div3都属于div0所创建的BFC区域下。

又因为id=div3的div又创建了一个BFC区域,所以div5div6就不再属于div0所创建的BFC区域内,而属于div3创建的BFC区域内。

知道了BFC的区域的划分,我们通过每一个实例,来对BFC的规则做一个演示和体会

BFC代码实例

1、内部的块级盒子会在垂直方向,一个接一个地放置。

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21
22        }
23        .div2{
24            opacity: 0.5;
25            background: rebeccapurple;
26            width: 100px;
27            height: 100px;
28        }
29        .BFC{
30            display: inline-block;
31        }
32    </style>
33</head>
34<body>
35    <div id="div0" class="main BFC">
36            <div id="div1" class="div1">元素1</div>
37            <div id="div2" class="div2">元素2</div>
38    </div>
39</body>
40</html>

结果:

我们看到我们给div0设置了一个BFC的css样式:display:inline-block,此时我们给div0创建了一个BFC。而它内部的div元素都带有默认的css属性:display:block,因此它们会生成块级盒子,在BFC区域内垂直排布。这就是我们大家都知道的常规流。

其实我们会发现我们当初学习HTML和CSS时,很多块级元素的规则其实就是BFC的规则。

2、块级盒子垂直方向的距离由margin决定。属于同一个BFC的两个相邻块级盒子的margin会发生重叠。

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .div2{
23            opacity: 0.5;
24            background: rebeccapurple;
25            width: 100px;
26            height: 100px;
27        }
28        .BFC{
29            display: inline-block;
30        }
31        .margin-100px{
32            margin: 100px;
33        }
34    </style>
35</head>
36<body>
37    <div id="div0" class="main BFC">
38            <div id="div1" class="div1 margin-100px">元素1</div>
39            <div id="div2" class="div2 margin-100px">元素2</div>
40    </div>
41</body>
42</html>

结果:

这就是BFC中经常发生的边距重叠的情况。而且重叠的情况会根据重叠的块级盒子的margin值有关,在这里即:div1的margin-bottom和div2的margin-top值有关系。

分三种情况:

当div1的margin-bottom和div2的margin-top值都为正数,则重叠时,取最大的值展示。

当div1的margin-bottom和div2的margin-top值一正一负时,则重叠时,取他们之间的差值展示。如下图展示:

当div的margin-bottom和div2的margin-top值都为负数,则重叠时,取他们绝对值最大的margin值。如下图展示:

如何解决margin边距重叠

根据BFC规则:属于同一个BFC的两个相邻块级盒子的margin会发生重叠。因此我们只要使div1与div2不属于同一个BFC即可:

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .div2{
23            opacity: 0.5;
24            background: rebeccapurple;
25            width: 100px;
26            height: 100px;
27        }
28        .BFC{
29            display: inline-block;
30        }
31        .margin-100px{
32            margin: 100px;
33        }
34
35
36    </style>
37</head>
38<body>
39    <div id="div0" class="main BFC">
40            <div id="div1" class="div1 margin-100px">元素1</div>
41            <div class="BFC">
42                    <div id="div2" class="div2 margin-100px">元素2</div>
43            </div>
44    </div>
45</body>
46</html>

此时我们将div2包裹在一个新的div下面,通过给这个新的div设置display:inline-block新创建了一个BFC,因此此时的div1和div2不在一个BFC区域中,所以他们的margin值不会发生重叠。

3、每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。

4、BFC的区域不会与float box重叠。

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .div2{
23            opacity: 0.5;
24            background: rebeccapurple;
25            width: 100px;
26            height: 100px;
27        }
28        .BFC{
29            display: inline-block;
30        }
31        .margin-100px{
32            margin: 100px;
33        }
34        .float-left{
35            float: left;
36        }
37
38
39    </style>
40</head>
41<body>
42    <div id="div0" class="main BFC">
43            <div id="div1" class="div1 margin-100px float-left">元素1</div>
44            <div id="div2" class="div2 margin-100px">元素2</div>
45    </div>
46</body>
47</html>

这里我们仔细想想为什么会发生这样的情况:

1、首先我们的div1和div2处于同一个BFC区域中,我们这里暂且把这个BFC称作BFC0; 2、我们给div1设置了float:left; 3、由于div1进行了漂浮,而div2与div1处于BFC0中,所以div2和div1还是会发生重叠;

要解决漂浮重叠,我们也可以通过BFC进行解决,我们依旧给div2放到一个新的BFC区域中,那么根据BFC的规则,BFC的区域不会与float box重叠,就可以解决。

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .div2{
23            opacity: 0.5;
24            background: rebeccapurple;
25            width: 100px;
26            height: 100px;
27        }
28        .BFC{
29            overflow: auto;
30        }
31        .margin-100px{
32            margin: 100px;
33        }
34        .float-left{
35            float: left;
36        }
37    </style>
38</head>
39<body>
40    <div id="div0" class="main BFC">
41            <div id="div1" class="div1 margin-100px float-left">元素1</div>
42            <div class="BFC">
43                    <div id="div2" class="div2 margin-100px">元素2</div>
44            </div>
45    </div>
46</body>
47</html>

结果:

此时我们通过给div2新建了一个BFC区域,因此它没有与div1漂浮发生重叠。

这时候仔细的小伙伴可能会问,根据BFC的规则1,为什么div2没有垂直方向独占一行?

这是因为div1发生了漂浮,它会影响它后面的一个元素,因此并不是div2没有在垂直方向独占一行,而是因为div1漂浮的缘故,div2和div1一起占了一行,而又因为新建了一个BFC,因此div2没有和div1重叠在一起,所以此时看起来他们并没有垂直排布。其实是div2独占了一行,而由于div1由于漂浮脱离了文档流,导致的。

5、BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之也如此。

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .div2{
23            opacity: 0.5;
24            background: rebeccapurple;
25            width: 100px;
26            height: 100px;
27        }
28
29        .child{
30            width: 50px;
31            height: 50px;
32            background: orange;
33            margin: 10px;
34        }
35        .BFC{
36            display: inline-block;
37        }
38        .margin-100px{
39            margin: 100px;
40        }
41        .float-left{
42            float: left;
43        }
44    </style>
45</head>
46<body>
47    <div id="div0" class="main BFC">
48            <div id="div1" class="div1 float-left">元素1</div>
49            <div id="div2" class="div2">
50                    元素2
51                    <div class="child"></div>
52                    <div class="child"></div>
53                    <div class="child"></div>
54            </div>
55
56    </div>
57</body>
58</html>

结果:

我们可以看到由于div1进行漂浮,div2中的文字和设置了child样式的div被受到了div1漂浮的影响。

我们给div2创建新的BFC区域,即可解决问题。

此时,div2不再受到div1的影响。

6、计算BFC的高度时,浮动元素也参与计算。

当我们使用漂浮的时候,我们经常会遇到高度塌陷的问题。例如:

 1<!DOCTYPE html>
 2<html lang="en">
 3<head>
 4    <meta charset="UTF-8">
 5    <meta name="viewport" content="width=device-width, initial-scale=1.0">
 6    <meta http-equiv="X-UA-Compatible" content="ie=edge">
 7    <title>Document</title>
 8    <script>
 9
10    </script>
11    <style>
12        .main{
13            margin: 10px;
14            border: 3px solid red;
15        }
16        .div1{
17            opacity: 0.5;
18            background: greenyellow;
19            width: 100px;
20            height: 100px;
21        }
22        .BFC{
23            display: inline-block;
24        }
25        .float-left{
26            float: left;
27        }
28
29    </style>
30</head>
31<body>
32    <div id="div0" class="main">
33        <div class="div1 float-left">元素1</div>
34    </div>
35</body>
36</html>

结果:

我们可以看到此时我们没有给div0设置BFC,同时使div1进行漂浮,我们看到div0计算高度的时候没有包含div1的高度。这就是我们所说的高度塌陷的情况。

我们也可以用BFC进行解决这个问题,我们给div0创建一个BFC,此时它在计算高度时,会同时包括div1的高度。

复盘

BFC其实就是CSS范畴的知识,它对块级元素生成的块级盒子进行了一些规则的限制,使这些块级盒子按照规则在html文档中排布和布局。或许你之前并没有系统的学习过BFC这个知识点,但你一定是通过经验之谈,对BFC多多少少是有了解的。

作者:丨大麦

地址:https://juejin.im/post/5b6065abf265da0fa00a2ec4

声明:本文是丨大麦原创,已获其授权原创发布

原文发布于微信公众号 - Android先生(cyg_24kshign)

原文发表时间:2018-08-07

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏视觉求索无尽也

Markdown:入门

在 Markdown 中,你只需要在文本前面加上 # 即可,同理、你还可以增加二级标题、三级标题、四级标题、五级标题和六级标题,总共六级,只需要增加 # 即可,...

1201
来自专栏偏前端工程师的驿站

CSS魔法堂:更丰富的前端动效by CSS Animation

 在《CSS魔法堂:Transition就这么好玩》中我们了解到对于简单的补间动画,我们可以通过transition实现。那到底多简单的动画适合用transti...

1994
来自专栏河湾欢儿的专栏

浮动与清除浮动

浮动 float半脱离文档流(对元素,脱离文档流;对内容,在文档流) 浮动的定义:使元素脱离文档流,按照指定方向发生移动,遇到父级边界或者相邻的浮动元素停了...

861
来自专栏Android开发经验

自定义view——圆形进度条的实现

1411
来自专栏偏前端工程师的驿站

CSS魔法堂:更丰富的前端动效by CSS Animation

1223
来自专栏练小习的专栏

可视化格式模型-包含块

一个元素box的定位和尺寸,有时候会跟某一矩形框有关,这个矩形框,就被称作元素的包含块。而元素会为它的子孙元素创建包含块,那么,是不是说,元素的包含块就是它的父...

2048
来自专栏超然的博客

Float 的那些事

  display:inline-block某种意义上的作用就是包裹(wrap),而浮动也有类似的效果。举个常见例子,或许您有实现宽度自适应按钮的经验,实现宽度...

993
来自专栏前端知识分享

第162天:canvas中Konva库的使用方法

2801
来自专栏进击的君君的前端之路

px、em、rem

1372
来自专栏小灰灰

im4java + imagemagic 搭建一个图片处理服务

imagemagic + im4java 进行图片处理 利用 imagemagic 对图片进行处理,java工程中,使用im4java来操作imagemagi...

2867

扫码关注云+社区

领取腾讯云代金券