首先放一下BFC的讲解文章史上最全面、最透彻的BFC原理剖析 - 掘金 (juejin.cn),这个大佬讲解BFC讲的很透彻,自己只是想手敲一遍加深印象。
clearfix和BFC的概念
BFC的相关概念
大家感兴趣的请移步开头那篇文章,不再赘述
clearfix的相关概念
clearfix是一种css技巧,它可以在不添加新标签的情况下,解决父元素中添加浮动子元素导致的相关问题,主要是父元素高度塌缩和父子元素外边距重叠这两个问题。
父元素高度塌缩
以圣杯模型In Search of the Holy Grail -- A List Apart为例,圣杯模型的布局代码如下
bash
<div id="header"></div><div id="container">
<div id="center" class="column"></div>
<div id="left" class="column"></div>
<div id="right" class="column"></div>
</div><div id="footer"></div>
样式代码大家可以去看一下原文,主要注意一下footer的样式代码,这里有一个clear的参数
arduino
#footer {
clear: both;
}
clear常用的有四个属性值,分别是none,left,right,both,对应的也是float的相关属性,这个属性的MDN定义是一个元素是否必须移动 (清除浮动后) 到在它之前的浮动元素下面。这样讲可能有点不容易理解,结合具体效果来讲解一下。 首先是正常的圣杯布局,为了方便观察我清除掉left、center和right的背景色
然后将container添加上显眼的红色背景,但实际上该样式并不会生效
footer在添加了clear:both
后被移动到了相邻元素的浮动子元素下面,但实际上并没有对相邻元素的高度造成影响,如果我清除掉footer的这个属性,会发现footer和header重叠了(因为container的子元素的浮动都是left,所以这里设置成clear:left
也有一样的效果,感兴趣自己尝试)
那么问题来了,clearfix是一种css技巧,它可以在不添加新标签的情况下,解决父元素中添加浮动子元素导致的相关问题,如何能不添加新标签(footer),同时还能达成这个效果呢?其实也不难猜,答案就是伪元素。其实感觉这里有点取巧的说法,伪元素就不是元素了吗!伪元素什么时候才能站起来!XXX!
说回正题,伪元素的相关概念大家自己搜一下,不再赘述,给container增加一个after伪元素,content设置为''(随便设置个字符然后可见性隐藏也是一样的效果,不过要同时把高度设为0),clear设置为left或者both,同时用display转为块级元素,就能用更精炼的代码实现类似footer的包裹效果,顺便还能撑起container的高度。
父子元素外边距重叠
接下来说第二个问题,父子元素共用了同一个外边距,这里用圣杯模型就不太合适了,因为有设定浮动和绝对定位的元素不会发生外边距折叠,具体可以看外边距重叠的MDN定义:掌握外边距折叠 - CSS:层叠样式表 | MDN (mozilla.org),在代码上的表现形式就是为什么大家搜到的常用clearfix的代码是display:table
,而不是display:block
。 先来看一下具体的问题表现,如果把圣杯模型中的left和right隐藏掉,同时取消container子元素的float属性,会得到下面的展示效果(为了保护眼睛我把container的背景色改成了灰蓝色)
这个时候如果我给center的上下外边距分别设置为10px,会发现实际效果似乎是给父元素container添加了外边距而非子元素center,我期望的效果是center相对container的上下边界出现10px的位移,同时container在高度上被拉伸20px,很明显我的期望效果没有达到
当我在代码里面把container::before
和container::after
的display:block
改为display:table
的时候,达到了了期望效果。下图只修改了before的display
下面按照自己的理解讲一下相关原理,当我给一个元素(比如伪元素 ::before
和 ::after
)设置了 display: table;
(或其他创建 BFC 的属性),我实际上在文档流中为该元素提供了一块"地盘",这个"地盘"是独立的布局区域,该元素里面的外边距不会和外部区域的外边距进行 collapse,也就是说不会与邻近块级盒子的外边距合并。
当我给 .container
添加 ::before
和 ::after
伪元素,并设置为创建 BFC 的属性后,这些伪元素创建了一个隔离区域,阻止了 .container
内的子元素(如 #center
)的外边距与 .container
自己的上外边距和下外边距进行合并(塌陷)。因为 BFC 规定了其内部的布局和外部是互不影响的,即使 #center
的 margin 有意图向外传递,也被 BFC 内的布局规则所限制在伪元素内部,进而使得 .container
的实际高度包含了 #center
的外边距,从而"增加了 container 的高度"。
这样总的代码就是
css
.container::after,
.container::before
{
content:'';
display:table;
clear:both;
}
但实际上自己对于这里的BFC还是有点不太理解,暂且留个疑问,如果后面有更清晰的理解了再维护更新
- BFC形成后,他的作用范围是什么, 理论上来说,BFC不会影响外部的渲染,为什么给伪元素设置了BFC,可以影响到父元素的展示效果。
- 其实和第一个是一个问题,为什么当我给伪元素设置了
display:table
或者其他的能达成BFC的效果后,#center
的外边距被拦截了(不太恰当的说法),同时还增加了#container
的高度。