理解CSS布局和BFC

编辑推荐: 掘金是一个高质量的技术社区,从 CSS 到 Vue.js,性能优化到开源类库,让你不错过前端开发的每一个技术干货。 点击链接查看最新前端内容,或到各大应用市场搜索「 掘金」下载APP,技术干货尽在掌握中。

CSS布局中有一些概念,一旦理解了这些概念,就能真正的提高你的CSS能力。这篇文章主要介绍的是关于块格式化上下文(Block Formatting Context),也就是大家俗称的BFC。你可能从未听说过这个术语,但只要你曾经使用过CSS布局,你就可能知道它是什么。理解BFC是什么,它有什么功能,以及如何创建一个BFC是非常有用的,这些能帮助你更好的理解CSS布局。

在这篇文章中,我将会通过几个很熟悉的示例来解释BFC。我还会介绍一个新的display的值,当你理解了BFC是什么的时候,你才能了解为什么需要这个值。也就能更好的理解它的真正意义。

什么是BFC

通过一个简单的float布局示例就能很好的理解BFC的行为。在下面的示例中,我们创建了一个盒子(其实在CSS中,每个元素都是一个盒子),这个盒子中包含了一个设置了浮动的图片和一段文本。如果有足够多的文本内容的时候,文本会围绕着图片(把整个图片包裹起来)。

<!-- HTML -->
<div class="outer">
    <div class="float">I am a floated element.</div>
    I am text inside the outer box.
</div>

/* CSS */

.outer {
    border: 5px dotted rgb(214,129,137);
    border-radius: 5px;
    width: 450px;
    padding: 10px;
    margin-bottom: 40px;
}

.float {
    padding: 10px;
    border: 5px solid rgba(214,129,137,.4);
    border-radius: 5px;
    background-color: rgba(233,78,119,.4);
    color: #fff;
    float: left;  
    width: 200px;
    margin: 0 20px 0 0;
}

文本围绕着浮动元素:

什么是BFC

如果在上面的基础上删除一些文本,就没有足够的文本去围绕图片(上例是一个浮动的元素),同时由于浮动元素脱离文档流,盒子元素的边框(包含浮动元素和文本的容器)高度就会随着文本的减少而降低(常被理解元素浮动之后致使其父容器坍塌)。

什么是BFC

上图再次证明,没有足够多的文本时,盒子元素边框的高度就会低于浮动元素的高度。

之所以会这样,那是当浮动一个元素时,盒子仍然保持原来的宽度,是文本所占的空间缩短了,才给浮动元素腾出位置,这就是为什么背景和边框能够看起来包裹住了浮动元素。

有两种方式可以解决这个布局问题。一种是使用clearfix黑魔法,就是在文本和图片(浮动元素)的下面插入一个元素,比如div,并将设置clear属性值为both。另外一种方法是使用overflow属性,把它设置为非默认值visible的值。

.outer {
    overflow: auto;
}

什么是BFC

使用overflow:auto后盒子就能包裹浮动元素。

overflow之所以能够有效是因为当它的值是非visible时会创建一个BFC,而BFC的一个特性就是包裹浮动元素。

使用Clearfix黑魔法时,除了在浮动的元素和文本最下面插入一个元素之外,更简单,也是最为经典的方式是使用CSS的伪元素::after或伪类:after。其实也就是大家常说的清除浮动,有关于这方面的详细介绍可以点击这里

BFC中布局中的迷你布局

你可以将BFC看作是页面中的一个迷你布局。一旦元素创建了一个BFC,它其中的所有元素都会被它包裹。正如我们所见的,当盒子变成BFC之后,它内部的浮动元素就再也不可能突破它的底部(也就是说,盒子不再会因内部元素浮动而坍塌)。除此之外,BFC还有一些有用的功能。

BFC可以阻挡外边距叠加(Margins Collapsing)

理解了margin,那么你又将掌握CSS的必杀技之一。在接下来的示例中,创建了一个backgroundgreydiv

这个div里有两个段落,div元素的margin-bottom:40px;设置,同时每个段落都有一个margin-topmargin-bottom20px的属性设置。

.outer {
    background-color: #ccc;
    margin: 0 0 40px 0;
}

p {
    padding: 0;
    margin: 20px 0 20px 0;
    background-color: rgb(233,78,119);
    color: #fff;
}

由于p元素的边缘与.outer元素的边缘之间没有任何东西,所以.outer元素与p元素的margin会叠加,p会与.outer的顶部与底部齐平,p对外的margin似乎与.outermargin合并了,使我们无法在段落的上下看到.outer的灰色背景。

Margins Collapsing

由于margin叠加,我们看到.outer内部上下没有灰色背景。

如果我们把.outer元素变成一个BFC,它就可以包裹住p以及pmargin,外边距不会发生叠加,.outer元素内部就会出现由p元素的margin顶出来的上下灰色背景。

.outer {
    background-color: #ccc;
    margin: 0 0 40px 0;
    overflow: auto;
}

Margins Collapsing

创建BFC之后,外边距不再叠加。

如果你对CSS的margin还不是非常的了解,建议你阅读@瑶姐写的margin的系列文章:

另外至于为什么BFC可以阻止外边距叠加,有关于这方面的深入介绍,建议阅读《深入理解BFC和Margin Collapse》一文。

一旦BFC创建,它就会阻止它内部的元素逃离并从盒子里伸出来。

一个BFC会停止去围绕浮动元素。你可能很熟悉BFC的这个特性,因为我们在有浮动元素的列类型布局中常用到。如果一个元素创建了BFC,它就不会去围绕(或者说包裹)任何浮动元素。看下面这个示例:

<div class="outer">
    <div class="float">I am a floated element.</div>
    <div class="text">I am text</div>
</div>

类名为.float的元素将会浮动在布局的左侧,类名为.text的元素将会在它后面并围绕.float元素。

文本围绕着浮动元素

我们可以通过给.text元素创建一个BFC来阻止这种围绕行为。

.text {
    overflow: auto;
}

.text元素建立BFC之后,文本就不再会围绕浮动元素了。

该方法也是我们创建浮动布局的基本方式。还需要注意的是浮动一个元素时也会给该元素创建BFC,也就是说此时.float.text元素都创建了对应的BFC,这也是无论右侧高度低于还是高于左侧两者都不会相互围绕的原因。

创建一个BFC的常用方式

除了使用overflow来创建BFC之外,还有一些CSS属性也可以创建BFC。比如上面我们所看见的,浮动一个元素也可以为该元素创建BFC,浮动元素会包裹它内部的所有元素。还有以下几种方式也可以创建BFC:

  • 使用position:absolute或者position:fixed
  • 使用display:inline-blockdisplay:table-cell或者display:table-caption,其中table-celltable-caption是表格相关元素对应默认CSS值,所以当你创建表格时,每个表格的单元格都会自动创建BFC
  • 另外当使用多列布局时,使用了column-span:all也可以创建BFC。Flexbox和Grid布局中的元素也会自动创建类似BFC的机制,只是它们被称为FFC(弹性格式上下文)和GFC(网格格式上下文)。这反映了它们所参与的布局类型。一个BFC表明他内部的元素参与了块级布避,一个FFC意味着它内部的元素参与了Flexbox布局。在实践中,这几种布局的结果是相似的,浮动元素会被包裹,外边距不会叠加。

创建BFC的新方式

使用overflow或其他的方法创建BFC时会有两个问题。首先,这些方法本身是有自身的设计目的,所以在使用它们创建BFC时可能会产生副作用。例如,使用overflow创建BFC后在某些情况下可能会看到出现一个滚动条或者元素内容被裁切。这是由于overflow属性的设计是用来让你告诉浏览器如何定义元素的溢出状态的。浏览器执行了它最基本的定义。

另一个问题是,即使在没有出现副作用的情况下,使用overflow也可能会使另一个开发人员感到困惑。他们可能会各种猜想:

这里为什么要把overflow的值设置为autoscroll?原来的开发人员这样做的意义是什么?原来的开发人员是想让这里出现滚动条吗?

最安全的做法应该是创建一个BFC时并不会带来任何副作用,它内部的元素都安全的呆在这个迷你布局中,这种方法不会引起任何意想不到的问题,也可以理解开发者的意图。CSS工作组也十分认同这种想法,所以他们定制了一个新的属性值:display:flow-root

你可以使用display:flow-root安全的创建BFC,来解决上文中提到的各种问题:包裹浮动元素、阻止外边距叠加和阻止围绕浮动元素。

Caniuse上display:flow-root各浏览器兼容情况。

有关于flow-root的详细介绍可以阅读早前整理的一篇教程《flow-root》。

浏览器对该属性的支持目前还是有限的,如果你觉得这个属性值很方便,请投票去让Edge也支持它。不过无论如何,你现在应该已经理解了什么是 BFC,以及如何使用 overflow 或其他方法来包裹浮动,以及知道了 BFC 可以阻止元素去环绕浮动元素,如果你想使用弹性或网格布局可以在一些不支持他们的浏览器中使用 BFC 的这些特性做降级处理。

理解浏览器如何布置网页是非常基础的。 虽然有时看起来无关紧要,但是这些小知识可以加快创建和调试 CSS 布局所需的时间。

扩展阅读

本文根据@Rachel Andrew的《Understanding CSS Layout And The Block Formatting Context》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.w3cplus.com/css/understanding-css-layout-block-formatting-context.html

返回顶部