CSS3浮动属性
写在前面的话
CSS 浮动(Float)最初主要用于实现图文混排,后来也被广泛用于网页布局。随着 Flexbox 和 Grid 的普及,浮动已经不再是现代网页布局的首选方案,但它仍然值得学习,因为它涉及 CSS 中几个重要概念:普通文档流、文字环绕、BFC 和高度塌陷。
浮动的基本概念
什么是浮动?
浮动是 CSS 提供的一种布局机制,通过 float 属性,使元素向其包含块的左侧或右侧移动,并允许周围的行内内容环绕它。
.box { float: left;}float 常见属性值:
| 属性值 | 说明 |
|---|---|
none | 不浮动,默认值 |
left | 向左浮动 |
right | 向右浮动 |
浮动元素会脱离普通文档流,但并不是完全不受布局规则约束。
浮动元素的特点
浮动主要具有以下几个特点:
- 脱离普通文档流:不再按照普通块级元素的布局方式占据空间。
- 可以横向排列:多个浮动元素在空间足够时可以并排。
- 具有文字环绕效果:周围的行内内容会避开浮动元素。
- 受到布局规则约束:不能随意覆盖前面已经布局的元素。
- 可能造成父元素高度塌陷:浮动元素不会按普通流的方式撑开父元素。
示例:浮动元素横向排列
<div class="box"> <div class="c1"></div> <div class="c2"></div> <div class="c3"></div></div>.box { width: 600px; border: 1px solid #000;}
.box > div { width: 200px; height: 200px; float: left;}
.box .c1 { background: orange; }.box .c2 { background: blue; }.box .c3 { background: green; }三个元素全部设置 float: left,并且父容器宽度足够,因此它们会横向排列。
如果取消 .c1 的浮动:
.box .c1 { float: none;}那么 .c1 会正常占据第一行,后面的 .c2 和 .c3 则在其下方浮动排列。
这是因为浮动元素虽然脱离普通文档流,但仍然受到前面元素位置的约束。这与后续的绝对定位的脱离文档流不一样
浮动与普通文档流的区别
普通块级元素通常按照从上到下的顺序排列。
而浮动元素会向左或向右移动,直到遇到容器边界、其他浮动元素,或者受到布局规则的限制。
需要注意:脱离普通文档流,不等于脱离所有布局规则。
例如:
<div class="box"> <div class="normal"></div> <div class="float"></div></div>.normal { width: 200px; height: 200px; background: orange;}
.float { width: 200px; height: 200px; background: blue; float: left;}蓝色盒子不会直接覆盖黄色盒子,而是从黄色盒子的下方开始浮动。但是,如果浮动元素后面出现普通块级元素,后者的盒子可能与浮动元素重叠,因为普通块级盒子的布局不会为浮动元素预留普通流空间。
上面说的是可能发生重叠,原因是:浮动元素脱离普通文档流,后面的普通块级盒子会忽略它占据的空间,但文字会避开它。主要区分是盒子还是文字
浮动实现文字环绕
文字环绕是浮动最典型的使用场景。
<div class="box"> <div class="c1"></div> <p> 这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。这是一段文章内容,当图片设置向左浮动后, 文字会自动围绕图片排列。 当文字超过图片高度时, 后面的文字会恢复占据完整的行宽。 </p></div><style> * { margin: 0; padding: 0; } .box { width: 600px; height: 400px; border: 1px solid #000; }
.box > div { width: 200px; height: 200px; float: left; }
.box .c1 { background: orange; }
.box p { border: 1px solid red; line-height: 20px; }</style>这里需要理解一个细节:
p的块级盒子不一定避开浮动元素。通过给p盒子加上边框可以观察到,p这个块级盒子,有一部分是被重叠的p内部的文字行会避开浮动元素。- 当文字排到浮动元素下方时,就能重新使用整行空间。
这也是为什么浮动能实现自然的图文混排。
BFC 规范和浏览器差异
什么是 BFC?
BFC,全称 Block Formatting Context(块级格式化上下文)。
它是 CSS 视觉格式化模型中的一种布局机制,决定了内部块级盒子如何排列,以及如何与浮动元素交互。
可以简单理解为:
BFC 为内部元素建立了一套相对独立的块级布局环境。
它不是一个 CSS 属性,而是一种由特定条件触发的布局机制。
BFC 的主要特点
| 特点 | 说明 |
|---|---|
| 内部布局独立 | 内部盒子的布局遵循所在 BFC 的规则 |
| 包含浮动高度 | 建立 BFC 的容器会计算内部浮动元素的高度 |
| 避开外部浮动 | BFC 的盒子在空间允许时会避开旁边的浮动 |
| 阻止部分 margin 折叠 | 不同 BFC 之间的垂直外边距不会发生折叠 |
需要注意,BFC 并不是完全隔离所有 CSS 行为。
例如,字体和颜色等可继承属性,仍然可以从父元素继承。
如何触发 BFC?
常见方式如下:
| CSS 写法 | 说明 |
|---|---|
display: flow-root | 专门创建 BFC,推荐(2017年支持) |
overflow: hidden | 创建 BFC,但可能裁剪溢出内容(上古时期教学经常采用的) |
overflow: auto | 创建 BFC,可能出现滚动条 |
float: left/right | 浮动元素自身建立 BFC |
position: absolute | 绝对定位元素建立独立的块级格式化上下文 |
display: inline-block | 建立 BFC |
display: flex | 创建 Flex 格式化上下文,不是 BFC |
display: grid | 创建 Grid 格式化上下文,不是 BFC |
注意:Flex 和 Grid 虽然也会建立独立的布局上下文,但它们不是 BFC。
示例:使用 flow-root 创建 BFC
<div class="box"> <div class="child"></div></div>.box { display: flow-root; border: 1px solid black;}
.child { width: 200px; height: 200px; background: orange; float: left;}虽然 .child 设置了浮动,但 .box 仍然能够包含浮动元素的高度。这是 flow-root 的重要用途。
BFC 如何避免外部浮动?
<div class="left"></div><div class="right"> 这里是右侧内容</div>.left { width: 200px; height: 150px; float: left; background: orange;}
.right { display: flow-root; background: lightblue;}.right 建立了 BFC,因此它的边框盒会避开左侧的浮动元素。如果剩余空间不足以容纳 .right,它可能被放置到浮动元素下方。这与普通块级盒子可能延伸到浮动元素后面的行为不同。
BFC 与浏览器差异
早期浏览器对 CSS 浮动、BFC 和元素尺寸的处理存在较多兼容性问题。
其中比较典型的是旧版 Internet Explorer 的 hasLayout 机制。
在 IE6、IE7 中,开发者有时使用:
.box { zoom: 1;}触发 hasLayout,从而解决部分浮动和布局异常。但是必须注意:**hasLayout** **并不等于 BFC。**它们是不同的布局机制,只是某些表现存在相似之处。对于现代 Chrome、Firefox、Safari 和 Edge,通常不需要再使用这些旧浏览器兼容技巧。
实际开发中优先使用:
.box { display: flow-root;}不过,BFC 的具体行为仍然要遵循 CSS 布局规范,不能将它理解成万能的样式隔离机制。
清除浮动
为什么需要清除浮动?
先看一个示例:
<div class="box"> <div class="child"></div></div>.box { border: 2px solid black;}
.child { width: 200px; height: 200px; background: orange; float: left;}此时 .child 脱离普通文档流,父元素 .box 不会按照普通块级子元素的方式计算它的高度。
因此,父元素可能出现高度塌陷。
所谓高度塌陷,就是:
父元素没有被内部浮动元素撑开,导致高度小于预期。
这可能造成后续元素布局异常、背景显示范围不正确,以及边框无法包围浮动元素等问题。
clear 属性
CSS 提供 clear 属性控制元素是否必须避开前面对应方向的浮动元素。
| 属性值 | 说明 |
|---|---|
none | 默认值,不清除浮动 |
left | 清除前面的左浮动影响 |
right | 清除前面的右浮动影响 |
both | 清除前面的左右浮动影响 |
示例:
<div class="box"> <div class="child"></div> <div class="clear"></div></div>.child { width: 200px; height: 200px; background: orange; float: left;}
.clear { clear: both;}.clear 会被放置到前面浮动元素的下方。
因为它仍然处于普通文档流中,父容器能够获得相应高度。
但这种方式需要额外添加一个没有实际语义的 HTML 元素,因此并不推荐。
使用伪元素清除浮动
传统开发中经常使用 ::after 实现清除浮动。
.clearfix::after { content: ""; display: block; clear: both;}使用方式:
<div class="box clearfix"> <div class="child"></div></div>它的原理是:
- 使用
::after创建一个伪元素。 - 伪元素作为父元素内部的最后一个子盒子。
clear: both使其避开前面的浮动元素。- 父元素因此能够包含相应的高度。
这种方案不需要增加额外的 HTML 标签,兼容性也比较好。
使用 overflow 清除浮动
.box { overflow: hidden;}overflow: hidden 能够建立 BFC,使父元素包含内部浮动元素的高度。
但存在一个问题:
超出容器的内容可能被裁剪。
例如,下拉菜单、阴影、绝对定位的装饰等溢出内容可能受到影响。
因此,不应该为了清除浮动而无条件使用 overflow: hidden。
使用 flow-root 解决高度塌陷
现代开发中,更推荐使用:
.box { display: flow-root;}它具有几个优点:
- 创建 BFC。
- 包含内部浮动元素的高度。
- 不需要额外 HTML 元素。
- 不会像
overflow: hidden一样主动裁剪溢出内容。 - 语义明确,专门用于建立新的块级格式化上下文。
需要区分两个概念:
**clear: both** 是清除前面浮动对自身位置的影响;**display: flow-root** 是通过创建 BFC,让容器包含内部浮动元素。
两者可以解决一些相似的布局问题,但原理并不相同。
清除浮动方案对比
| 方法 | 原理 | 推荐程度 |
|---|---|---|
额外元素 + clear | 让普通流元素避开浮动 | 不推荐 |
::after + clear | 利用伪元素清除浮动 | 兼容旧项目时使用 |
overflow: hidden | 创建 BFC | 特定场景使用 |
display: flow-root | 创建 BFC 并包含浮动 | 现代开发推荐 |
示例代码:
额外元素 + clear: both(不推荐)
<div class="box"> <div class="child"></div> <div class="clear"></div></div>.box { border: 1px solid black;}.child { width: 200px; height: 200px; background: orange; float: left;}.clear { clear: both;}原理: 在浮动元素后面添加一个普通块级元素,使用 clear: both 让它移动到浮动元素下方,从而撑开父容器。
缺点: 需要增加没有实际语义的 HTML 标签。
::after + clear: both(传统推荐)
<div class="box clearfix"> <div class="child"></div></div>.box { border: 1px solid black;}
.child { width: 200px; height: 200px; background: orange; float: left;}
.clearfix::after { content: ""; display: block; clear: both;}原理: 通过 ::after 在父元素内部创建一个伪元素,再利用 clear: both 撑开父容器。其实就是第一种方式的衍生,把标签换成伪元素了
优点: 不需要额外的 HTML 标签,兼容性好。
overflow: hidden(特定场景使用)
<div class="box"> <div class="child"></div></div>.box { border: 1px solid black; overflow: hidden;}
.child { width: 200px; height: 200px; background: orange; float: left;}原理: overflow: hidden 会创建 BFC,使父元素在计算自动高度时包含内部浮动元素。
缺点: 超出容器的内容可能被裁剪,比如阴影、下拉菜单等。
display: flow-root(现代推荐)
<div class="box"> <div class="child"></div></div>.box { border: 1px solid black; display: flow-root;}
.child { width: 200px; height: 200px; background: orange; float: left;}原理: 直接创建 BFC,使父元素在计算自动高度时包含内部浮动元素。
优点: 不需要额外标签或伪元素,也不会因为创建 BFC 而裁剪溢出内容。
记住两种原理即可:
clear:让一个普通流中的盒子避开前面的浮动,借助它撑开父容器。BFC:让父容器在计算自动高度时包含内部浮动元素。
总结
浮动、BFC 和清除浮动之间存在直接联系:
- 浮动:让元素向左或向右移动,脱离普通文档流,同时实现文字环绕。
- BFC:规定一组块级盒子的布局行为,能够处理浮动高度包含、外部浮动避让等问题。
- 清除浮动:解决浮动引起的布局影响,尤其是父元素高度塌陷问题。
现代开发可以记住以下原则:
- 页面整体布局:优先使用 Flexbox 和 Grid。
- 文章图片文字环绕:使用
float。 - 需要清除前面的浮动影响:使用
clear。 - 需要父元素包含浮动高度:优先考虑
display: flow-root。 - 维护旧项目:认识
clearfix和overflow等传统处理方式。
浮动并没有过时,只是已经不适合承担整个网页布局的主要职责。理解它的规则,才是学习浮动的真正目的。
拓展示例
clear: both:
-
给
.c2增加clear: both;,清除.c1浮动对.c2的影响,顺便撑开了盒子,box2也可以正常写在后面 -
如果取消 clear: both,高度也不会塌陷,但是
.c2会被.c1重叠了,不会塌陷是因为被.c2这个没有浮动的盒子撑开并非.c1 -
特别注意的一点:元素是会被重叠,文字不会,这是之前多次提到的
-
假设C2也浮动呢?虽然可以依旧在C2加clear: both,但是此时高度仍然不会被撑起来,所以这里就需要多加dmo节点或者伪元素
-
父盒子的宽度如果不够后面盒子的宽度,后面的盒子就会自动掉到下面
<!doctype html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> * { margin: 0; padding: 0; } .box { width: 400px; /* 让内部盒子撑开高度 */ /* height: 400px; */ background-color: #ccc; } .c1 { width: 200px; height: 200px; background-color: red; float: left; } .c2 { width: 200px; height: 200px; background-color: green; /* 清除浮动对自己的影响 */ clear: both; } .box2 { width: 200px; height: 200px; background-color: blue; } </style> </head> <body> <div class="box"> <div class="c1">C1左浮动</div> <div class="c2">C2正常</div> <span>span</span> <span>span</span> </div> <div class="box2">box2</div> </body></html>文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!














