浮动(float)最初是为了实现文字环绕图片的效果而设计的。后来被广泛用于页面布局,虽然现在 Flexbox 和 Grid 已经取代了浮动布局,但理解浮动和 BFC 仍然对排查布局问题很有帮助。
浮动基础#
float 属性#
.float-left { float: left;}
.float-right { float: right;}
.float-none { float: none; /* 默认值 */}文字环绕#
这是浮动最初的设计目的:
<article> <img src="photo.jpg" class="float-left" alt="" /> <p>这段文字会环绕在图片的右侧...</p></article>.float-left { float: left; margin-right: 1rem; margin-bottom: 0.5rem;}浮动的特性#
当元素浮动后:
- 脱离文档流:不再占据正常的空间
- 向左或向右移动:直到碰到容器边缘或另一个浮动元素
- 变成块级元素:可以设置宽高
- 行内内容会环绕:文字和行内元素会绕开浮动元素
/* 浮动后可以设置宽高 */span { float: left; width: 100px; /* 生效,即使 span 原本是行内元素 */ height: 100px;}清除浮动#
🙋 什么是”高度塌陷”?
当父元素只包含浮动子元素时,父元素的高度会变成 0:
<div class="parent"> <div class="child" style="float: left;">浮动子元素</div></div>.parent { border: 2px solid red; /* 高度为 0,只能看到边框线 */}方法一:clear 属性#
在浮动元素后添加一个清除浮动的元素:
<div class="parent"> <div class="child" style="float: left;">浮动子元素</div> <div style="clear: both;"></div></div>clear 的取值:
left:清除左浮动right:清除右浮动both:清除两侧浮动
方法二:clearfix(伪元素)#
使用伪元素自动清除,无需额外 HTML:
.clearfix::after { content: ''; display: block; clear: both;}<div class="parent clearfix"> <div class="child" style="float: left;">浮动子元素</div></div>这是传统项目中最常用的方法。
方法三:overflow#
父元素设置 overflow: hidden 或 overflow: auto:
.parent { overflow: hidden;}这会触发 BFC,但可能会裁剪溢出的内容。
方法四:display: flow-root(推荐)#
现代浏览器支持的最佳方案:
.parent { display: flow-root;}专门用于清除浮动,没有副作用,语义清晰。
BFC(块格式化上下文)#
BFC(Block Formatting Context)是页面上的一个独立渲染区域,内部元素的布局不会影响外部。
触发 BFC 的条件#
以下任一条件都会创建 BFC:
/* 根元素 */html {}
/* float 不为 none */.bfc { float: left;}
/* position 为 absolute 或 fixed */.bfc { position: absolute;}
/* display 为特定值 */.bfc { display: inline-block;}.bfc { display: flow-root;} /* 推荐 */.bfc { display: flex;}.bfc { display: grid;}.bfc { display: table-cell;}
/* overflow 不为 visible */.bfc { overflow: hidden;}.bfc { overflow: auto;}
/* contain 为特定值 */.bfc { contain: layout;}BFC 的特性#
1. 包含浮动子元素#
BFC 会包含其内部的浮动元素,解决高度塌陷:
.parent { display: flow-root; /* 创建 BFC */}2. 阻止外边距合并#
BFC 可以阻止垂直外边距合并:
<div class="box1">Box 1</div><div class="bfc-wrapper"> <div class="box2">Box 2</div></div>.box1 { margin-bottom: 30px;}
.box2 { margin-top: 20px;}
.bfc-wrapper { display: flow-root; /* 阻止 box2 的 margin 与 box1 合并 */}/* 现在间距是 30px + 20px = 50px */3. 不与浮动元素重叠#
BFC 区域不会与浮动元素重叠:
<div class="float-box">浮动</div><div class="main-content">主内容</div>.float-box { float: left; width: 200px; height: 100px; background: #3b82f6;}
.main-content { display: flow-root; /* 创建 BFC,不会环绕浮动元素 */ background: #f3f4f6;}这可以用来实现两栏布局。
实战案例#
经典两栏布局#
<div class="layout"> <aside class="sidebar">侧边栏</aside> <main class="content">主内容区</main></div>.layout { display: flow-root; /* 清除浮动 */}
.sidebar { float: left; width: 250px; min-height: 400px; background: #f3f4f6; padding: 1rem;}
.content { display: flow-root; /* 不与 sidebar 重叠 */ min-height: 400px; background: white; padding: 1rem; margin-left: 260px; /* sidebar 宽度 + 间距 */}三栏布局(圣杯布局)#
<div class="holy-grail"> <main class="main">主内容(DOM 顺序优先)</main> <nav class="left">左侧导航</nav> <aside class="right">右侧边栏</aside></div>.holy-grail { padding-left: 200px; padding-right: 150px;}
.holy-grail::after { content: ''; display: block; clear: both;}
.main { float: left; width: 100%; min-height: 300px; background: white;}
.left { float: left; width: 200px; min-height: 300px; margin-left: -100%; position: relative; left: -200px; background: #f3f4f6;}
.right { float: left; width: 150px; min-height: 300px; margin-left: -150px; position: relative; right: -150px; background: #e5e7eb;}🔶 这种布局现在用 Flexbox 或 Grid 实现更简单,这里只是展示浮动布局的原理。
媒体对象#
经典的”图片+文字”模式:
<div class="media"> <img src="avatar.jpg" class="media-image" alt="" /> <div class="media-body"> <h4>用户名</h4> <p>评论内容...</p> </div></div>.media { display: flow-root;}
.media-image { float: left; width: 64px; height: 64px; border-radius: 50%; margin-right: 1rem;}
.media-body { display: flow-root; /* 不环绕图片 */}
.media-body h4 { margin: 0 0 0.5rem;}
.media-body p { margin: 0; color: #6b7280;}多列等高布局#
利用 BFC 实现等高列:
<div class="columns"> <div class="column"> <p>短内容</p> </div> <div class="column"> <p>这是一段很长很长的内容...</p> <p>还有更多内容...</p> </div></div>.columns { display: flow-root; background: #e5e7eb; /* 这个背景色会填充"短"列的空白 */}
.column { float: left; width: 50%; padding: 1rem; background: white; /* 使用负 margin 技巧 */ padding-bottom: 9999px; margin-bottom: -9999px;}🔶 这是个老技巧,现代布局用 Flexbox 的 align-items: stretch 更简单。
浮动 vs 现代布局#
| 特性 | 浮动 | Flexbox/Grid |
|---|---|---|
| 设计目的 | 文字环绕 | 布局 |
| 使用复杂度 | 需要清除浮动 | 简单直观 |
| 垂直居中 | 困难 | 容易 |
| 等高列 | 需要 hack | 自动支持 |
| 响应式 | 需要媒体查询 | 更灵活 |
| 浏览器支持 | 所有浏览器 | 现代浏览器 |
何时使用浮动#
- 真正的文字环绕效果
- 维护老项目
- 需要支持极老的浏览器
何时使用 Flexbox/Grid#
- 几乎所有布局场景
- 新项目
- 复杂的响应式布局
常见问题#
🤔 为什么我的浮动元素跑到容器外面了?
父元素没有包含浮动子元素。使用 display: flow-root 或 clearfix 解决。
🤔 浮动元素旁边的内容为什么会跑到浮动元素下面?
浮动元素脱离了文档流。如果不想环绕,给旁边的元素也触发 BFC。
🤔 display: flow-root 和 overflow: hidden 有什么区别?
功能上都能创建 BFC 清除浮动。但 overflow: hidden 会裁剪溢出内容,flow-root 没有副作用,推荐使用后者。
浮动和 BFC 是 CSS 布局发展历程中的重要概念。虽然现代开发中 Flexbox 和 Grid 是更好的选择,但理解这些概念有助于排查遗留问题和理解 CSS 的工作原理。下一篇我们将深入学习 Flexbox,它是现代 CSS 布局的基石。