参考答案:
在介绍BFC之前,需要先给大家介绍一下文档流。
我们常说的文档流其实分为定位流
、浮动流
、普通流
三种。
如果元素的属性 position
为 absolute
或 fixed
,它就是一个绝对定位元素。
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响,而元素具体的位置由绝对定位的坐标决定。
它的定位相对于它的包含块,相关CSS属性:top
、bottom
、left
、right
;
对于 position: absolute
,元素定位将相对于上级元素中最近的一个relative、fixed、absolute
,如果没有则相对于body;
对于 position:fixed
,正常来说是相对于浏览器窗口定位的,但是当元素祖先的 transform
属性非 none
时,会相对于该祖先进行定位。
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
普通流其实就是指BFC中的FC。FC(Formatting Context
),直译过来是格式化上下文,它是页面中的一块渲染区域,有一套渲染规则,决定了其子元素如何布局,以及和其他元素之间的关系和作用。
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行。块级元素则会被渲染为完整的一个新行。
除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
先看下MDN上关于BFC的定义:
块格式化上下文(
Block Formatting Context
,BFC
) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。
具有 BFC
特性的元素可以看作是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,并且 BFC
具有普通容器所没有的一些特性。
通俗一点来讲,可以把 BFC
理解为一个封闭的大箱子,箱子内部的元素无论如何翻江倒海,都不会影响到外部。
除了 BFC,还有:
IFC
(行级格式化上下文)- inline
内联GFC
(网格布局格式化上下文)- display: grid
FFC
(自适应格式化上下文)- display: flex
或display: inline-flex
注意:同一个元素不能同时存在于两个 BFC
中。
MDN上对于BFC的触发条件写的很多,总结一下常见的触发方式有(只需要满足一个条件即可触发 BFC 的特性):
<html>
float
值为 left
、right
overflow
值不为 visible
,即为 auto
、scroll
、hidden
display
值为 inline-block
、table-cell
、table-caption
、table
、inline-table
、flex
、inline-flex
、grid
、inline-grid
position
值为 absolute
、fixed
margin box
)的左边与包含块边框盒(border box
)的左边相接触(从右向左的格式的话,则相反),即使存在浮动BFC是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然。我们可以利用BFC的这个特性来做很多事。
左列浮动(定宽或不定宽都可以),给右列开启 BFC。
1<div> 2 <div class="left">浮动元素,无固定宽度</div> 3 <div class="right">自适应</div> 4</div>
1* { 2 margin: 0; 3 padding: 0; 4} 5.left { 6 float: left; 7 height: 200px; 8 margin-right: 10px; 9 background-color: red; 10} 11.right { 12 overflow: hidden; 13 height: 200px; 14 background-color: yellow; 15}
效果:
这即是上面说的 BFC 的特性之一:浮动盒的区域不会和 BFC 重叠
兄弟元素之间的外边距重叠
1<div> 2 <div class="child1"></div> 3 <div class="child2"></div> 4</div>
1* { 2 margin: 0; 3 padding: 0; 4} 5.child1 { 6 width: 100px; 7 height: 100px; 8 margin-bottom: 10px; 9 background-color: red; 10} 11.child2 { 12 width: 100px; 13 height: 100px; 14 margin-top: 20px; 15 background-color: green; 16}
效果:
两个块级元素,红色 div 距离底部 10px,绿色 div 距离顶部 20px,按道理应该两个块级元素相距 30px 才对,但实际却是取距离较大的一个,即 20px。
块级元素的上外边距和下外边距有时会合并(或折叠)为一个外边距,其大小取其中的较大者,这种行为称为外边距折叠(重叠),注意这个是发生在属于同一 BFC 下的块级元素之间
根据 BFC 特性,创建一个新的 BFC 就不会发生 margin 折叠了。比如我们在他们两个 div 外层再包裹一层容器,加属性 overflow: hidden
,触发 BFC,那么两个 div 就不属于同个 BFC 了。
1<div> 2 <div class="parent"> 3 <div class="child1"></div> 4 </div> 5 <div class="parent"> 6 <div class="child2"></div> 7 </div> 8</div>
1.parent { 2 overflow: hidden; 3} 4 5/* ... */
这个关于兄弟元素外边距叠加的问题,除了触发 BFC 也有其他方案,比如你统一只用上边距或下边距,就不会有上面的问题。
这种情况存在父元素与其第一个或最后一个子元素之间(嵌套元素)。
如果在父元素与其第一个/最后一个子元素之间不存在边框、内边距、行内内容,也没有创建块格式化上下文、或者清除浮动将两者的外边距 分开,此时子元素的外边距会“溢出”到父元素的外面。
1<div id="parent"> 2 <div id="child"></div> 3</div>
1* { 2 margin: 0; 3 padding: 0; 4} 5#parent { 6 width: 200px; 7 height: 200px; 8 background-color: green; 9 margin-top: 20px; 10} 11#child { 12 width: 100px; 13 height: 100px; 14 background-color: red; 15 margin-top: 30px; 16}
如上图,红色的 div 在绿色的 div 内部,且设置了 margin-top
为 30px,但我们发现红色 div 的顶部与绿色 div 顶部重合,并没有距离顶部 30px,而是溢出到父元素的外面计算。即本来父元素距离顶部只有 20px,被子元素溢出影响,外边距重叠,取较大的值,则距离顶部 30px。
解决办法:
这样就能实现我们期望的效果了:
当容器内子元素设置浮动时,脱离了文档流,容器中总父元素高度只有边框部分高度。
1<div class="parent"> 2 <div class="child"></div> 3</div>
1* { 2 margin: 0; 3 padding: 0; 4} 5.parent { 6 border: 4px solid red; 7} 8.child { 9 float: left; 10 width: 200px; 11 height: 200px; 12 background-color: blue; 13}
解决办法:给父元素触发 BFC,使其有 BFC 特性:计算 BFC 的高度时,浮动元素也会参与计算
1.parent { 2 overflow: hidden; 3 border: 4px solid red; 4}
上面我们都是用的 overflow: hidden
触发 BFC,因为确实常用,但是触发 BFC 也不止是只有这一种方法。
如上面写的所示,可以设置float: left;
,float: right;
,display: inline-block;
,overflow: auto;
,display: flex;
,display: table;
,position
为 absolute
或 fixed
等等,这些都可以触发,不过父元素宽度表现不一定相同,但父元素高度都被撑出来了。
当然实际运用可不是随便挑一个走,还是根据场景选择。
最近更新时间:2024-08-10