全回顾扫盲css之BFC

研究BFC好几天好几天了,感觉各种博客虽然多,但好多都互相矛盾呢,所幸追根问底的搞一搞。

BFC定义

BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

BFC布局规则

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算

生成规则

  • 根元素
  • float属性不为none
  • position为absolute或fixed
  • display为inline-block, table-cell, table-caption, flex, inline-flex
  • overflow不为visible

根元素:

都在说这个根元素,但这个跟元素究竟是body呢,还是html呢,还是window呢,window有点扯了,css里面没它什么事。我直接试一下。在body第一个div加一个margin-top,按照BFC布局规则,BFC内部子元素不会影响到外面的元素,如果不存在BFC,父级元素会因为子元素的margin-top而出现向下移动。结果发现body并没有与上边距拉开距离,这就符合BFC的规则了,那,body就有BFC。

display为inline-block, table-cell, table-caption, flex, inline-flex

这个我第一反应是,为啥没有display:block~~~为毛。但是有的博客上写的是display:block是可以生成BFC的。测试一下就清楚了。还是按照上面那个规则,BFC子元素不会对外面产生影响。

//  css
#container{
    background: blue;
    overflow: hidden;
}
.box{
    background: green;
    height:80px;
    display: block;
}
.box-box{
    background: red;
    height:50px;
    width: 50px;
    margin-top:20px;
}

//  html
<section id="container">
    <article class="box box1">
        <div class="box-box"></div>
    </article>
</section>

这里测试结果显然,display:block属性并没有为其创建BFC,而改用display:inline-block之后,子元素的margin被包在元素里面了。

BFC的作用一般有两个:1.解决margin重叠、2.清除浮动

margin重叠

根据BFC的布局规则,同属于一个BFC的两个相邻的Box的margin会重叠。由于根元素本身就是一个BFC,所以默认写在根元素里面的box都会有margin重叠。如例子

//  css
*{
    margin:0;
    padding:0;
}
#container{
    overflow: hidden;
    border: 1px solid red;
}
.box{
    height:80px;
    width:50px;
}
.box1{
    background: blue;
    margin-bottom:20px;
}
.box2{
    margin-top:50px;
    background: yellow;
}

//  html
<section id="container">
    <article class="box box1">
    </article>
    <article class="box box2">
    </article>
</section>

这里#container里面有两个子元素,垂直左侧排列。这符合BFC的布局规则。里面两个元素,上面的margin-bottom:20px,下面的margin-top:50px,最后两个margin出现了重叠,最终两个块的距离为50px。 为了解决这个问题,我们可以给子元素添加BFC。

//  css
*{
    margin:0;
    padding:0;
}
#container{
    overflow: hidden;
    border: 1px solid red;
}
.box{
    height:80px;
    width:50px;
}
.box1{
    background: blue;
    margin-bottom:20px;
}
.box2{
    margin-top:50px;
    background: yellow;
}
.box-bfc{
    overflow: auto;
}

//  html
<section id="container">
    <article class="box box1">
    </article>
    <section class="box-bfc">
        <article class="box box2">
        </article>
    </section>
</section>

但是BFC是父级对子元素创建的封闭空间,自己创建,是封闭不了margin的,如下面这种做法,我给.box1添加BFC,显然不会有什么作用。

//  css
*{
    margin:0;
    padding:0;
}
#container{
    overflow: hidden;
    border: 1px solid red;
}
.box{
    height:80px;
    width:50px;
}
.box1{
    background: blue;
    margin-bottom:20px;
    overflow: auto;
}
.box2{
    margin-top:50px;
    background: yellow;
}

//  html
<section id="container">
    <article class="box box1">
    </article>
    <article class="box box2">
    </article>
</section>

清除浮动还是闭合浮动?

关于BFC清除浮动,我看到了一个观点觉得值得一提。用clear操作,叫清除浮动,用BFC,应该叫闭合浮动。

关闭clear清除浮动,这里有个栗子

//  css
*{
    margin:0;
    padding:0;
}
#container{
    border: 1px solid red;
}
.box{
    width:50px;
}
.box1{
    background: blue;
    margin-bottom:20px;
}
.box2{
    margin-top:50px;
    background: yellow;
}
.cl{
    clear: both;
}
.fl{
    float: left;
    width:50%;
}
.fr{
    float: right;
    width:50%;
}

//  html
<section id="container">
    <section class="box">
        <div class="fl">left left left left left left left left left </div>
        <div class="fr">right right right right right right right right </div>
    </section>
    <div class="cl"></div>
    <section class="main">main main main main main main main main main main </section>
</section>

这里我们可以看到,最然#container的高度被撑起来了,浮动被清除了,但是.box却出现了高度塌陷。当然,这个问题好解决,把.cl放到.box的最后一个元素的位置,.box的高度就撑开了。但是最终向表达的是,BFC跟这种清楚浮动的方式,还是有不同点的。我们可以给.box加一个display: inline-block;,来保证内部浮动不会影响到外部,但这个 方式,更像是把浮动闭合在内部,而不是去清除它。

最后再总结下。BFC用处其实只有一个,就是给当前元素创建一个隔离层,将内部子元素与外部元素隔离开。

随机浏览