Skip to content

浮动与 BFC

浮动(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;
}

浮动的特性#

当元素浮动后:

  1. 脱离文档流:不再占据正常的空间
  2. 向左或向右移动:直到碰到容器边缘或另一个浮动元素
  3. 变成块级元素:可以设置宽高
  4. 行内内容会环绕:文字和行内元素会绕开浮动元素
/* 浮动后可以设置宽高 */
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 的取值:

方法二:clearfix(伪元素)#

使用伪元素自动清除,无需额外 HTML:

.clearfix::after {
content: '';
display: block;
clear: both;
}
<div class="parent clearfix">
<div class="child" style="float: left;">浮动子元素</div>
</div>

这是传统项目中最常用的方法。

方法三:overflow#

父元素设置 overflow: hiddenoverflow: 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 布局的基石。