常规流之块级格式化上下文(Block Formatting Contexts)

∥☆過路亽.° 提交于 2020-01-12 18:50:17

  在css2.1中,常规流包括块框(block boxes)的块格式化(block formatting),行内框(inline boxes)的行内格式化(inline formatting),块级框(block-level-boxes)或行内级框(inline-level-boxes)的相对定位。常规流中的框属于一个格式化上下文,可能是块或者是行内,但不能同时都是。块级框参与块级格式化上下文,行内级框参与行内级格式化上下文。今天我们先来说说块级格式化上下文,也就是我们常说的BFC。

一.形成块级格式化上下文

  • 绝对定位元素(fixed其实是absolute的一个子集)
  • display为inline-block,table-cell,table-caption,flex,inline-flex(这里有一点要注意的,display-table本身不会形成BFC,但是它会产生匿名框,其中包含的dispaly:table-cell元素会形成BFC)
  • overflow不为visible
  • 根元素
  • float属性不为none

  这里要说明的是这些是形成块格式化上下文,而不是说是参与块级格式化上下文,这两个概念很容易弄混,大家可以仔细体会下。块格式化上下文是一个独立的渲染区域,而且只会有块级框(block-level box)来参与,它规定内部的块级框如何布局,与这个区域的外部毫不相干。

二.块格式化上下文中的特性

    在块格式化上下文中,框会一个接一个的被垂直放置,他们的起点是一个包含块的顶部。

  两个兄弟框之间的垂直距离取决于margin属性。在BFC中相邻的块级元素的垂直边距会折叠。

  在BFC中,每一个元素的左外边(left margin边界)与包含块的左边相接触(对于从右到左的格式化,右边距接触包含块右边)。即使存在浮动也是如此(尽管一个元素的内容区域会由于浮动而压缩),除非这个元素也形成了一个新的BFC。

  计算BFC高度的时候,浮动子元素也会参与计算。

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

三.块级格式化上下文的作用

  我们之所以要了解一些东西,无非是需要有现实的意义和作用,不然谁管它(笑)。

  那么BFC有什么作用呢,那就得从BFC的特性说起了。下面,我们会根据一些具体的例子来一个个说明。

  1.清除浮动

  我们上面说了,计算BFC高度的时候,浮动子元素也会参与计算,而浮动子元素造成的塌陷想必大家也都非常了解,那么如果父元素形成了BFC,是不是就可以包含浮动子元素了呢?直接看例子(为了直观我就不贴可运行代码了):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>BFC清除浮动</title>
    <style>
        *{margin:0; padding: 0;}
        .wrap-wrap{ height: 150px;}
        .wrap{ width: 300px; background-color :#fcc; color: #fff;}
        .son1,.son2{ float: left; width: 100px; height: 100px; background-color:red;}
        .son2{ background-color:blue; }
        .wrap-bfc{ overflow: hidden;}
    </style>
</head>
<body>
<div class="wrap-wrap">
    <div class="wrap">
        wrap
        <div class="son1">son1</div>
        <div class="son2">son2</div>
    </div>
</div>
<div class="wrap wrap-bfc">
        wrap
    <div class="son1">son1</div>
    <div class="son2">son2</div>
</div>
</body>
</html>

  运行结果如下:

  我们通过一个overflow:hidden使下面的wrap形成了BFC,它高度的计算中浮动子元素也会参与,自然就包含了浮动元素,从而达到了清除浮动的目的。当然,不止overflow:hidden可以清除浮动,各位可以自行试试其他属性。

  2.防止垂直margin重叠

  在同一BFC中相邻的块级元素的垂直边距会折叠。那么如果这两个元素不在一个BFC中了会发生什么呢,继续看例子:

  

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>防止边距折叠</title>
    <style>
        *{margin:0; padding: 0;}
        .wrap,.wrap1,.wrap2{ width: 200px; height: 100px; background-color :#fcc; color: #fff;}
        .son1,.son2{ width: 50px; height: 20px; margin: 10px; background-color:red;}
        .son2{ background-color:blue; }
        .wrap1{ overflow: hidden; background-color:lime; }
        .wrap2{ overflow: hidden; background-color:lime; }
        .new-wrap{ overflow: hidden;}
    </style>
    
</head>
<body>
    <div class="wrap">
        <div class="son1">son1</div>
        <div class="son2">son2</div>
        wrap
    </div>
    <p>——————分割符————</p>
    <div class="wrap1">
        <div class="son1">son1</div>
        <div class="son2">son2</div>
        wrap1
    </div>
    <p>——————分割符————</p>
    <div class="wrap2">
        <div class="son1">son1</div>
        <div class="new-wrap">
            <div class="son2">son2</div>
        </div>
        wrap2
    </div>
</body>
</html>

 

  运行结果如下:

  这里有两点要说。

  1).wrap1与son1的margin折叠

  我们先看wrap,son1是有个margin-top,但是图中给我们的感觉是没有,反而是它的父元素wrap有一个margin-top。为什么呢,这个就要看magrin折叠的说明了,这个也是标准中的内容:

  In this specification, the expression collapsing margins means that adjoining margins (no non-empty content, padding or border areas or clearance separate them) of two or more boxes (which may be next to one another or nested) combine to form a single margin. 所有毗邻的两个或更多盒元素的margin将会合并为一个margin共享之。毗邻的定义为:同级或者嵌套的盒元素,并且它们之间没有非空内容、Padding或Border分隔。 

  可知嵌套的盒元素也会Collapsing Margins,就不难知道为什么会这样了。而在wrap1中,同样的结构,也没有非空内容、Padding或Border分隔,为什么又不折叠了呢?这里就要知道什么叫毗邻了:

 Two margins are adjoining if and only if:

  • both belong to in-flow block-level boxes that participate in the same block formatting context
  • no line boxes, no clearance, no padding and no border separate them (Note that certain zero-height line boxes (see 9.4.2) are ignored for this purpose.)
  • both belong to vertically-adjacent box edges, i.e. form one of the following pairs:
    • top margin of a box and top margin of its first in-flow child
    • bottom margin of box and top margin of its next in-flow following sibling
    • bottom margin of a last in-flow child and bottom margin of its parent if the parent has 'auto' computed height
    • top and bottom margins of a box that does not establish a new block formatting context and that has zero computed 'min-height', zero or 'auto' computed 'height', and no in-flow children

  我就不一个个翻译了,就看第一条,这些margin都处于普通流中,并在同一个BFC中。我自己的理解是下面这样的,不一定正确,如果知道的同学还请指正:

  wrap1的overflow:hidden属性形成了一个新的BFC,son1就参与了这个新的BFC。而wrap1本身是在根元素形成的BFC种,由此两个就不在同一个BFC中了,也就不是毗邻的了,自然margin不会折叠。

  2).son1与son2的边距折叠。

  根据上面一点说的,son1和son2是满足margin折叠的条件的,那么如果我们给son2包裹个new-wrap,并让它形成BFC,自然就没有边距折叠了。

 

  3.自适应两栏布局。

  这个直接上代码吧,根据例子来说,比较直观

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>自适应布局</title>
    <style>
        *{margin:0; padding: 0;}
        body {
            position: relative;
            color: #fff;
        }
        .aside {
            width: 100px;
            height: 150px;
            float: left;
            background: #f66;
        }
     
        .main {
            height: 200px;
            background: #fcc;
        }
    </style>
</head>
<body>
    <div class="aside">float aside</div>
    <div class="main">main</div>
</body>
</html>

  运行结果:

  

  这里首先要说的是main的位置问题。在BFC中,每一个元素的左外边(left margin边界)与包含块的左边相接触(对于从右到左的格式化,右边距接触包含块右边),这里虽然有float的aside,但是main的左边依然与包含块的左边接触。

  而如果我们对main设置这样的样式:main:overflow:hidden,结果如下:

 

  当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。为什么呢:

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

  

四.总结

  今天我们主要分析了什么是BFC、怎么形成BFC以及BFC的作用。其中有一些我总结个人的理解,希望对大家有帮助。另外,在css3的草案中,对这个概念做了改动,将Block formatting context 叫做 flow root,触发方式也发生了变化:The value of 'position' is neither "static" nor "relative".fixed作为absolute的一个子类也会形成flow root,有兴趣的同学可以自己去了解下。好了,就这么多了,我写东西都是准备好了然后一口气,后面再一点点修改,初成文难免会有错漏,还请大家多多指正。下一章会分析下行内级格式化上下文的相关。

 

 

参考:

  1.KB010: 常规流( Normal flow )

  2.w3c盒模型

  3.w3c常规流

  4.前端精选文摘:BFC 神奇背后的原理

  

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!