引言
在前端CSS布局里,浮动绝对是又爱又恨的存在!日常做图文混排、多列布局都离不开它,但只要开启浮动,高度塌陷、布局错乱、边距重叠等奇葩bug就会接踵而至,让不少新手头疼不已。其实这些问题都不是bug,而是浮动的特性导致的!而BFC就是CSS官方自带的布局神医,专门专治浮动引发的各类布局疑难杂症。不用啃枯燥的官方文档,也不用死记硬背晦涩规则
一、文档流
在讲浮动定位之前,我们要先了解什么是文档流。文档流就是浏览器在渲染页面时,会遵照从上往下,从左往右,依次排列,这种页面的排板方式就是文档流。
二、浮动布局
那什么是浮动布局呢?他最初被官方创建出来的意义是文字环绕,用一张图解释一下什么是文字环绕:
如图所示,图片被周边文字环绕排布。实现原理十分简单:只需给<img>图片标签添加 float: left 样式,即可快速实现图文混排的文字环绕效果。
<style>
img{
float: left;
}
</style>
<body>
<div class = "page">
<img width="200" src="https://ts1.tc.mm.bing.net/th/id/OIP-C.ZjqbZElwdeux67YIjN1tkgHaEK?cb=thfc1falcon&rs=1&pid=ImgDetMain&o=7&rm=3" alt="">
<p>
  不少前端小伙伴写 JS 时总被数据类型坑:null被 typeof 错判成对象、数组识别为 Object,原生数值用 instanceof 判断屡屡出错,面试还总被深挖底层原理。本文细数 JS
全部数据类型,详解三种常用校验方式的优缺点与底层逻辑,搭配实操案例帮你按需选型,轻松避开类型判断各类 bug。
作者:咪饭只吃一小碗
链接:https://juejin.cn/post/7646480731196375091
来源:稀土掘金
</p>
</div>
</body>
使用浮动定位会让元素脱离标准文档流—— 虽然它不会覆盖文字,但当页面中存在其他容器时,很容易引发父容器高度塌陷问题,最终直接影响后续元素的正常排版与布局。举个例子:
<style>
*{
margin: 0;
padding: 0;
}
.item{
width: 200px;
height: 100px;
float: left;
}
.item:nth-child(1) {
background-color: #ed4949;
}
.item:nth-child(2) {
background-color: #dfef26;
}
.item:nth-child(3) {
background-color: #5df13c;
}
</style>
</head>
<body>
<ul>
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
<!-- <div class = "clear"></div> -->
</ul>
<h2>Hello world</h2>
</body>
</html>
运行结果如下:
我们希望把 hello world 显示在三个小方块的正下方,可问题在于:这三个方块都设置了浮动,导致它们脱离了文档流,最终引发父容器高度塌陷。而我们并不希望后面的内容受到浮动影响,那该怎么清除浮动带来的负面影响呢?接下来,我就为大家讲解几种常用的清除浮动方法。
三、清除浮动的负面效果
3.1. 直接给父容器设置高度
站在上帝视角分析,直接给 ul 固定高度 height: 100px 确实能临时修复塌陷问题、实现预期布局,但这种硬编码写死高度的方式,并不符合前端工程化的开发思路。并不推荐这种方法。
ul{
height: 100px;
}
3.2 在浮动元素的末尾增加一个空容器,设置一个 clear : both
就像这样:
<style>
.clear{
clear: both;
}
</style>
<body>
<ul>
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
<div class = "clear"></div>
</ul>
<h2>Hello world</h2>
</body>
该方案虽能清除浮动,倘若项目里有上百处浮动布局,就要凭空新增上百个空 div,DOM 冗余严重、加重页面渲染负担,实际开发不推荐。
3.3 为父容器设置 after 伪元素,在伪元素上 clear : both
就像这样:
<style>
ul::after{
content: '';
clear: both;
display: block;
}
</style>
<body>
<ul>
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>
<h2>Hello world</h2>
</body>
这种方式就很好的解决浮动的负面效果,且不会产生冗余 DOM、增加页面渲染损耗,是开发中值得推荐的清浮动方案。
3.4 给被影响的元素设置 clear: both;
就像这样:
<style>
h2{
clear: both;
}
</style>
<body>
<ul>
<li class="item">1</li>
<li class="item">2</li>
<li class="item">3</li>
</ul>
<h2>Hello world</h2>
</body>
这样也可以达到我们想要的结果,但是我们还是不推荐,因为这不符合程序员写代码的逻辑,最好是父容器内部的矛盾问题,就在父容器里面自己解决,而非修改后续兄弟元素的样式。
3.5 将父容器设置为 BFC 容器
这最后一种方法也是全文的重中之重,只需把浮动元素的父级容器触发为 BFC 独立渲染区域,既能自动撑开父盒子高度、解决高度塌陷,从根源隔绝浮动对外层与后续兄弟元素的布局干扰,无需新增冗余 DOM 标签,也不用改动页面其他元素样式。
四、BFC容器
在 HTML 布局中,一直存在一个经典问题:父子元素的 margin-top 会发生重叠(外边距塌陷) 。我们直接用代码来直观理解:
<style>
.parents{
width: 100%;
height: 500px;
background-color: green;
margin-top: 100px;
}
.child{
width: 100%;
height: 200px;
background-color: rgb(255, 0, 200);
margin-top: 50px;
}
</style>
<body>
<div class = "parents">
<div class = "child">
</div>
</div>
</body>
运行结果如下:
图中绿色是父容器,粉色是子容器。按照正常逻辑,子容器设置了 margin-top: 50px,应该距离父容器顶部 50px 才对。但实际效果却是:子元素直接带着父元素一起往下跑,两者的外边距合并在了一起。这就是典型的margin 重叠问题,而 BFC 正是专门用来解决这类布局 bug 的核心机制。
4.1 BFC 的渲染规则
- BFC 容器内部的子元素也是从上往下,从左往右排列
- BFC 容器是一个独立的拥有特殊渲染规则的容器,它内部的子元素不会影响外部
- BFC 容器在计算高度的时候,会将浮动的子元素的高度也计算在内
4.2 如何创建一个 BFC 容器
给元素添加以下任意一种 CSS 属性,即可生成 BFC 容器:
- overflow: hidden || auto || overlay || scroll;
- position: absolute || fixed
- float: left || right
- display: flex || grid || inline-xxxx;
五、总结
- 浮动初衷:实现文字环绕图文效果,浮动元素会脱离标准文档流
- 浮动副作用:造成父容器高度塌陷,打乱页面正常布局
- 清除浮动(不推荐):固定父级高度、新增空div、给后续元素清浮动
- 清除浮动(推荐) :父级after伪元素清浮动、父容器开启BFC
- BFC作用:独立渲染区域,解决浮动高度塌陷、父子margin外边距重叠问题
- BFC渲染规则:内部正常排列、内外布局互不干扰、计算高度包含浮动元素
- 触发BFC方式:overflow非visible、绝对/固定定位、设置浮动、flex/grid/行内块等display属性