Fork me on GitHub
代码改变世界

CSS之BFC(块级格式化上下文)

2015-07-30 13:57  todayhappy  阅读(2875)  评论(0编辑  收藏  举报

看了不少关于BFC的文章,就总结一下。终于应该算是明白了!

其实要说BFC,就要说普通流(normal flow),就要说IFC(内联格式化上下文),在一起都说了,才能讲的明白。

普通流说白了就是怎样把文档中的元素等自上而下一个一个的呈现出来,这些元素怎么在页面中摆放,而这个呈现过程就是普通流

那么普通流是怎么样把页面布局呈现的呢?就是通过BFC和IFC,还有一个relative positioning(相对位移),今天重点讲解BFC和IFC

BFC名字很高大上,说白了就是一个规则,这个规则应用于块级元素(div,p)上。

IFC这个规则应用于内联元素(span,em,i)上。

在文档呈现开始的时候,会自动创建一个BFC和IFC,来对整个页面进行布局,在没有我们通过设置一些属性,来创建一个新的BFC的时候,整个文档就这一个BFC和IFC,所以所有的元素都要使用这个规则。

在普通流中,所有的盒子(不管是内联盒子(内联元素等)还是块级盒子(块级元素等))都要属于一个格式化上下文,不是属于块级格式化上下文就是属于内联格式化上下文,但是不能同时属于两者,块级元素布局遵循块级格式化上下文的规则,内联元素布局遵循内联格式化上下文的规则来进行布局.就是这两个规则使得页面的所有元素有序的布局,才呈现出我们所看到的web页面。

什么是BFC,IFC

BFC,IFC,就是控制元素如何进行布局。

BFC规则:

1.如果给一个元素创建了一个BFC,就相当于创建了一个新的容器,容器内和容器外中的元素不会相互影响。外边的BFC规则,不会对容器里的BFC产生影响,而容器里面的BFC也不会对容器外的BFC产生影响,也就是相互隔绝,互不影响。

2.盒子的布局开始是从包含容器的顶部开始的。

3.同一个BFC中,在两个相邻的块级元素中,垂直margin会发生折叠

4.每个盒子的左边界都要紧靠包含容器左边界(这也就解释了为什么块级元素都是单独成一行的,如果不单独成行,第二个盒子的左边界怎么紧靠包含容器的左边界);

这第四个是最重要的布局规则

IFC规则:

1.盒子是水平一个接一个的排列,水平的margin,内边距,边框是可以有的。

2.垂直方向的对齐,可能是底部对齐,顶部对齐,也可能是基线对齐(这个是默认的);ps.这里的盒子应该是指的内联元素的盒子(span,strong等)和匿名内联盒子(只有文本,没有内联元素包含,自动创建的),他们合称内联盒子,一个或者多个内联盒子组成一个行框,行框的宽度由包含块和出现的浮动决定的(为什么有浮动呢,后面解释);行框的高度决定看我的这篇文章(css之line-height);一定要分清楚,行框和内联盒子的关系,要不然我所说的你就不太可能理解

3.行框中的内联盒子的高度小于行框的高度时,内联盒子的垂直方向的对齐方式取决于vertical-align属性

4.当一个行框水平不能容纳内联盒子时,他们将会在垂直方向上产生多个行框,他们上下一个挨着一个,但是不会重叠

5.一般来说,行框的左边界紧挨着包含容器的左边界,行框的右边界紧挨着包含容器的右边界,(是两个边都紧挨着)。然而,浮动盒子可能存在于包含边框边界和行框边界之间(后面解释这种情况);

6.多个内联盒子的宽度小于包含他们的行框时,他们在水平方向的分布取决于text-align属性(默认是left)

能产生新的BFC的属性:

1.float的值不为none。
2. overflow的值不为visible。
3.display的值为table-cell, table-caption, inline-block中的任何一个。
4.position的值不为relative和static。

只要给元素设置这些属性,则这些元素容器就不受外面的BFC约束了,他会给自己和他包含的元素应用新的BFC。也就是现在这些BFC平起平坐,你管不着我,我管不着你,只是我们两个的BFC规则是一样的。

如果你上面这些没有看懂的话,通过代码一定能看懂。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <style>
    body,div{
        margin:0;
        padding:0;
    }
        #box1,#box2,#box3{
            width:100px;
            height:110px;
            border: 1px solid red;
        }
        #box4{
            width:500px;
            border:1px solid red;
            height:100px;
        }
        #box4Child{
            width:100px;
            height: 50px;
            border: 1px solid black;
            float:left;
        }
    </style>
</head>
<body>
    <div id="box1"></div>
    <div id="box2"></div>
    <div id="box3">
        <span>我是内联元素盒子</span>我是内联匿名元素盒子<em>我也是内联元素盒子</em>
    </div>
    <div id="box4"><div id="box4Child"></div><span>我是内联元素盒子</span>我是内联匿名元素盒子<em>我也是内联元素盒子</em></div>
</body>
</html>

文档解析我就从body开始说起,我就形象一点说,

1.当普通流遇见body元素时,一看你是块级元素,应用BFC规则,所以,你要从你包含容器html元素顶部开始,左边紧靠他的左边,于是body就布局好了

2.接下来就是body里面的的box1了,普通流一看,你也是块级元素,你也要应用BFC规则,因为你是第一个body的第一个元素,所以从body容器的顶部开始布局,你的左边也要紧靠body的左边,并且你后面的元素要距离你10px,于是乎,box1就布局好了

3.box2开始了,box2跟普通流说你看box1宽度才100px,你让我在他后面吧,我们两个在一行才200px,普通流说不行,BFC的规则是你的左边必须紧靠包含容器(body元素)的左边,于是乎box2就只能自己一行了,(这也就是解释了为什么块级元素单独成行),普通流说你看你的margin-top和box1的margin-bottom是相邻的,根据BFC你们必须折叠,于是他们两个之间的距离就10px,而不是20px;

4.同理,box3跟类似上面的,于是box3就布局好了;

5.现在进行box3的内部了,IFC说,span是内联元素应该应用我的规则,我先创建一个行框(行框是他的左边挨着包含框的左边,右边挨着包含框的右边),这时发现一个行框太小,不能包含的了这个内联盒子,于是,就在下面又创建了一个行框,来包含这个内联盒子。这次两个行框终于把span内联盒子装下了,接下来是又是一个盒子,这次是个匿名内联盒子,既然都是内联的,就挨着span内联盒子继续吧,发现也是放不下,就又创建了一个内联盒子,下面的em也是那样我就不说了,balabala。

6. 接下来开始布局box4,一看是块级元素就使用BFC。

7. 进行box4内部布局,一看是块级元素但是呢她又有float属性,这是就创建一个新的BFC,这时就不受BFC规则的约束了。就不需要独占一行等规则了,但是呢,这又牵扯到float布局定位机制,float的一些特性,float是这样的,比如设置左浮动,那么它的左边一定要紧挨着包含元素的左边或者是另一个浮动元素的右边。多了我就不说了,看官方文档。这时box4child就布局好了,接下来就布局后面的东西了,一看是一个内联元素,好吧,就创建一个行框,这时要注意了上面IFC规则的第五条的后半部分,也就是说,现在在这里,这个行框的左边界不在紧挨着包含块的左边界了他也是可以挨着浮动元素的边界的,于是就产生了图中的效果,后面的东西同理上面就不多说了。

仅仅是个人理解,如有不对欢迎指正交流!

 

ps。之前写了一个爬取指定网站的算是小爬虫吧,使用nodejs写的,里面我添加了爬取博客园,csdn的关于web的版块,segmentfault问答,segmentfault文章,百度贴吧的JavaScript吧,w3ctech,w3cfuns等,我也就常去这几个网站了。界面我就以简洁为主。现在我就一直使用它来看文章,主要是简单快捷方便;地址:小爬虫

 W3C官方文档:http://www.w3.org/TR/CSS21/visuren.html#normal-flow

css定位机制之一:普通流