浮动曾经是实现多栏布局的核心手段,但用得不好就会出现各种诡异现象:图片把文字盖住了、两个盒子叠在了一起、父元素高度突然变成0导致背景消失。这些问题的根源都指向同一件事——浮动元素脱离了文档流。要彻底解决重叠问题,得先弄明白浮动到底做了什么,再针对不同场景选择合适的处理方式。

浮动为什么会导致元素重叠
CSS中的float属性会让元素脱离标准文档流,向左或向右移动,直到碰到父容器的边缘或者另一个浮动元素为止。脱离文档流意味着什么?意味着这个元素不再向父元素汇报自己的高度,也不再与块级元素抢占垂直方向的位置。
这里有一个非常关键的行为差异:浮动元素虽然脱离了文档流,但它并不会完全“无视”其他内容。块级元素会当浮动元素不存在一样向上补位,而行内内容和文字却会主动给浮动元素“让路”,环绕在浮动元素周围。这就是为什么图片设置浮动后文字会环绕图片,但如果文字所在的元素有背景色或边框,背景和边框会直接穿到图片下面去,看起来就像被图片压住了一样。
举个典型例子:一个左浮动的红色盒子,后面跟一个普通的蓝色盒子。蓝色盒子会整体向上移动到红色盒子的同一行位置,两者发生重叠,红色浮动盒子会盖在蓝色盒子上面。而如果蓝色盒子里面装的是纯文字,文字会避开红色盒子环绕显示,蓝色盒子的背景却依然会被盖住。理解了这个行为,后面所有的解决方案就都容易看懂了。
使用clear属性清除浮动重叠
最直接的解决办法是使用clear属性。它可以作用在浮动元素后面的元素上,告诉浏览器这个元素的左侧、右侧或两侧不允许出现浮动元素,从而把它“推”到浮动元素的下方。
.float-box {
float: left;
width: 200px;
height: 100px;
background: red;
}
.normal-box {
clear: both; /* 左右两侧都不允许有浮动,元素被推到浮动元素下方 */
background: blue;
height: 100px;
}clear的取值有left、right、both和none。实际开发中用both最省心,不用关心浮动方向。需要注意,clear只对块级元素有效,如果给行内元素设置是无效的。另外它解决的是浮动元素与后续兄弟元素的重叠问题,如果问题出在父容器高度塌陷上,光靠给兄弟元素加clear并不够优雅。
更通用的做法是给父容器末尾追加一个空元素并设置clear,也就是常说的“空div清除法”。这种方法直观但会引入无意义的标签,污染HTML结构,现在一般不推荐,但它引出了下面更现代的伪元素方案。
利用BFC解决浮动重叠
BFC全称块级格式化上下文,它是一个独立的渲染区域。BFC有一个重要特性:BFC内部的浮动元素也会参与容器高度的计算,同时BFC区域不会与外部浮动元素发生重叠。利用这两个特性,几乎可以一劳永逸地处理浮动带来的重叠问题。
触发BFC的方式很多,常用的包括:overflow: hidden、overflow: auto、display: flow-root、display: inline-block、position: absolute等。以最经典的场景为例,父元素包含浮动子元素导致高度塌陷,只需给父元素设置overflow: hidden,父元素就能重新包裹住浮动子元素:
.parent {
overflow: hidden; /* 触发BFC,包住内部浮动元素,解决高度塌陷 */
border: 2px solid #333;
}
.child {
float: left;
width: 100px;
height: 80px;
margin: 10px;
background: orange;
}不过overflow: hidden有个明显副作用:超出容器的内�会被裁剪,如果里面恰好有下拉菜单、弹出提示之类的元素就会被切掉。现代浏览器推荐的方案是display: flow-root,它专门为创建BFC而生,没有任何副作用,缺点是老版本IE不支持,需要根据项目兼容性决定。
伪元素清除浮动与布局替代方案
目前工程实践中使用最广泛的还是伪元素清除法。它在父元素上通过::after伪元素生成一个看不见的块级内容,并对其设置clear,效果等同于追加了一个空div,但完全不动HTML结构:
.clearfix::after {
content: "";
display: block; /* 或者使用 table,兼容更老的浏览器 */
clear: both;
height: 0;
visibility: hidden;
}
/* 兼容IE6/7的经典写法 */
.clearfix {
*zoom: 1;
}使用时只需给包含浮动元素的父容器加上clearfix类即可。这个方案来自Bootstrap等知名框架,稳定可靠,唯一要注意的是必须保证content属性存在,否则伪元素根本不会生成。
最后想说的是,浮动的本职工作从来不是布局。如今实现多栏布局、图文环绕等需求,flex和grid是更好的选择,它们不脱离文档流,天然不会产生重叠和高度塌陷问题。只有文字环绕图片这种场景,浮动依然是不可替代的。如果项目中出现大量浮动,不妨重新审视一下布局方案,改用弹性布局往往能从根源上消灭这一类重叠问题。综合来看:简单场景用display: flow-root,需要兼容老浏览器用伪元素清除法,新项目则优先考虑直接用flex布局替代浮动。