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;
}
文本围绕着浮动元素:
Image may be NSFW.
Clik here to view.
如果在上面的基础上删除一些文本,就没有足够的文本去围绕图片(上例是一个浮动的元素),同时由于浮动元素脱离文档流,盒子元素的边框(包含浮动元素和文本的容器)高度就会随着文本的减少而降低(常被理解元素浮动之后致使其父容器坍塌)。
Image may be NSFW.
Clik here to view.
上图再次证明,没有足够多的文本时,盒子元素边框的高度就会低于浮动元素的高度。
之所以会这样,那是当浮动一个元素时,盒子仍然保持原来的宽度,是文本所占的空间缩短了,才给浮动元素腾出位置,这就是为什么背景和边框能够看起来包裹住了浮动元素。
有两种方式可以解决这个布局问题。一种是使用clearfix黑魔法,就是在文本和图片(浮动元素)的下面插入一个元素,比如div
,并将设置clear
属性值为both
。另外一种方法是使用overflow
属性,把它设置为非默认值visible
的值。
.outer {
overflow: auto;
}
Image may be NSFW.
Clik here to view.
使用overflow:auto
后盒子就能包裹浮动元素。
overflow
之所以能够有效是因为当它的值是非visible
时会创建一个BFC,而BFC的一个特性就是包裹浮动元素。
使用Clearfix黑魔法时,除了在浮动的元素和文本最下面插入一个元素之外,更简单,也是最为经典的方式是使用CSS的伪元素
::after
或伪类:after
。其实也就是大家常说的清除浮动,有关于这方面的详细介绍可以点击这里。
BFC中布局中的迷你布局
你可以将BFC看作是页面中的一个迷你布局。一旦元素创建了一个BFC,它其中的所有元素都会被它包裹。正如我们所见的,当盒子变成BFC之后,它内部的浮动元素就再也不可能突破它的底部(也就是说,盒子不再会因内部元素浮动而坍塌)。除此之外,BFC还有一些有用的功能。
BFC可以阻挡外边距叠加(Margins Collapsing)
理解了margin
,那么你又将掌握CSS的必杀技之一。在接下来的示例中,创建了一个background
为grey
的div
。
这个div
里有两个段落,div
元素的margin-bottom:40px;
设置,同时每个段落都有一个margin-top
和margin-bottom
为20px
的属性设置。
.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
似乎与.outer
的margin
合并了,使我们无法在段落的上下看到.outer
的灰色背景。
Image may be NSFW.
Clik here to view.
由于margin
叠加,我们看到.outer
内部上下没有灰色背景。
如果我们把.outer
元素变成一个BFC,它就可以包裹住p
以及p
的margin
,外边距不会发生叠加,.outer
元素内部就会出现由p
元素的margin
顶出来的上下灰色背景。
.outer {
background-color: #ccc;
margin: 0 0 40px 0;
overflow: auto;
}
Image may be NSFW.
Clik here to view.
创建BFC之后,外边距不再叠加。
如果你对CSS的
margin
还不是非常的了解,建议你阅读@瑶姐写的margin
的系列文章:
margin
系列之布局篇margin
系列之bug巡演margin
系列之bug巡演(二)margin
系列之bug巡演(三)margin
系列之内秀篇margin
系列之内秀篇(二)margin
系列之外边距折叠margin
系列之与相对偏移的异同margin
系列之百分比margin
系列之keyword auto另外至于为什么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
元素。
Image may be NSFW.
Clik here to view.
我们可以通过给.text
元素创建一个BFC来阻止这种围绕行为。
.text {
overflow: auto;
}
Image may be NSFW.
Clik here to view.
.text
元素建立BFC之后,文本就不再会围绕浮动元素了。
该方法也是我们创建浮动布局的基本方式。还需要注意的是浮动一个元素时也会给该元素创建BFC,也就是说此时.float
和.text
元素都创建了对应的BFC,这也是无论右侧高度低于还是高于左侧两者都不会相互围绕的原因。
创建一个BFC的常用方式
除了使用overflow
来创建BFC之外,还有一些CSS属性也可以创建BFC。比如上面我们所看见的,浮动一个元素也可以为该元素创建BFC,浮动元素会包裹它内部的所有元素。还有以下几种方式也可以创建BFC:
- 使用
position:absolute
或者position:fixed
- 使用
display:inline-block
、display:table-cell
或者display:table-caption
,其中table-cell
和table-caption
是表格相关元素对应默认CSS值,所以当你创建表格时,每个表格的单元格都会自动创建BFC - 另外当使用多列布局时,使用了
column-span:all
也可以创建BFC。Flexbox和Grid布局中的元素也会自动创建类似BFC的机制,只是它们被称为FFC(弹性格式上下文)和GFC(网格格式上下文)。这反映了它们所参与的布局类型。一个BFC表明他内部的元素参与了块级布避,一个FFC意味着它内部的元素参与了Flexbox布局。在实践中,这几种布局的结果是相似的,浮动元素会被包裹,外边距不会叠加。
创建BFC的新方式
使用overflow
或其他的方法创建BFC时会有两个问题。首先,这些方法本身是有自身的设计目的,所以在使用它们创建BFC时可能会产生副作用。例如,使用overflow
创建BFC后在某些情况下可能会看到出现一个滚动条或者元素内容被裁切。这是由于overflow
属性的设计是用来让你告诉浏览器如何定义元素的溢出状态的。浏览器执行了它最基本的定义。
另一个问题是,即使在没有出现副作用的情况下,使用overflow
也可能会使另一个开发人员感到困惑。他们可能会各种猜想:
这里为什么要把
overflow
的值设置为auto
或scroll
?原来的开发人员这样做的意义是什么?原来的开发人员是想让这里出现滚动条吗?
最安全的做法应该是创建一个BFC时并不会带来任何副作用,它内部的元素都安全的呆在这个迷你布局中,这种方法不会引起任何意想不到的问题,也可以理解开发者的意图。CSS工作组也十分认同这种想法,所以他们定制了一个新的属性值:display:flow-root
。
你可以使用display:flow-root
安全的创建BFC,来解决上文中提到的各种问题:包裹浮动元素、阻止外边距叠加和阻止围绕浮动元素。
Caniuse上display:flow-root
各浏览器兼容情况。
有关于
flow-root
的详细介绍可以阅读早前整理的一篇教程《flow-root》。
浏览器对该属性的支持目前还是有限的,如果你觉得这个属性值很方便,请投票去让Edge也支持它。不过无论如何,你现在应该已经理解了什么是 BFC,以及如何使用 overflow
或其他方法来包裹浮动,以及知道了 BFC 可以阻止元素去环绕浮动元素,如果你想使用弹性或网格布局可以在一些不支持他们的浏览器中使用 BFC 的这些特性做降级处理。
理解浏览器如何布置网页是非常基础的。 虽然有时看起来无关紧要,但是这些小知识可以加快创建和调试 CSS 布局所需的时间。
扩展阅读
- BFC相关教程 @w3cplus
- Understanding Block Formatting Contexts in CSS
- 关于CSS-BFC深入理解
- CSS:BFC 最熟悉的陌生人
- CSS之BFC详解
- CSS: The block formatting context
- Block Formatting Contexts
- CSS 盒模型、解决方案、BFC 原理讲解
- CSS深入理解流体特性和BFC特性下多栏自适应布局
- 关于对CSS中BFC的理解
本文根据@Rachel Andrew的《Understanding CSS Layout And The Block Formatting Context》所译,整个译文带有我们自己的理解与思想,如果译得不好或有不对之处还请同行朋友指点。如需转载此译文,需注明英文出处:https://www.smashingmagazine.com/2017/12/understanding-css-layout-block-formatting-context/。
如需转载,烦请注明出处:https://www.w3cplus.com/css/understanding-css-layout-block-formatting-context.html