原文链接: Fyerl’s Blog
说起 BFC 其实有点像闭包在大多数人印象中的感觉,平时都用过,但在不了解定义的情况下大多数人却又不知道这就是 BFC。之所以会想了解下什么是 BFC,是因为前些日的一个简单且常见的排版问题
HTML 代码结构如下
<div class="form-item">
<span class="label">登录名</span>
<div class="content">
<input type="text" placeholder="请输入登录名">
</div>
</div>
label 的宽度是自适应的,content 需填充满此行剩余的区域。常规方法通过 flex 布局,很简单
.form-item {
display: flex;
}
.content {
flex: 1;
}
但是 flex 的兼容性还是不够向下的,于是搜索了一下,得到了这么个方案
.label {
float: left;
}
.content {
overflow: hidden;
}
label 给了个 float 可以理解,但 content 写了一个 overflow: hidden 是什么意思?实则这里的 content 就形成了一个 BFC,所以还是先回到 BFC 这个概念上
什么是 BFC
BFC 即(Block Format Context)块级格式化范围,是 CSS2.1 中用于规定块级盒子的渲染布局方式
如何触发创建一个 BFC
- root: 页面的根元素
- display: inline-block | flex | flow-root
- position: absolute | fixed
- overflow: hidden | auto | scroll
以上条件满足任一便会触发创建一个 BFC,同时也可以看出这些属性的设置会产生一些额外的效果,比如仅仅是想触发 BFC,却使用了 overflow: scroll 导致元素出现了滚动条,所以具体使用哪种方式触发 BFC,还是需要结合实际的业务场景
BFC 的特性以及使用场景
一、消除外边距折叠
<style>
.block {
background: #eee;
overflow: hidden;
}
.item {
height: 44px;
margin: 12px 0;
background: #666;
}
</style>
<body>
<div class="block">
<p class="item"></p>
<p class="item"></p>
</div>
</body>
如上,两个 item 均存在上、下 margin,理想情况下,两个 item 之间间距应是 24px,但结果只有 12px,这便是外边距折叠,兄弟元素外边距不同时,取最大值。这种行为只存在于兄弟元素在同一 BFC 下这种情形。若想消除外边距折叠,对上述代码做一些改造,使兄弟元素存在于不同 BFC 之中即可
<style>
.block {
background: #eee;
overflow: hidden;
}
.item-wrapper {
overflow: hidden;
}
.item {
height: 44px;
margin: 12px 0;
background: #666;
}
</style>
<body>
<div class="block">
<div class="item-wrapper">
<p class="item"></p>
</div>
<div class="item-wrapper">
<p class="item"></p>
</div>
</div>
</body>
此时 item-wrapper 便形成了一个 BFC,解决了外边距折叠问题。相信大家遇到这种情况习以为常地会加一层外层元素再给个 overflow: hidden,但为什么 overflow: hidden 就能消除折叠,其实背后是 BFC 的原理
二、清除浮动
<style>
.block {
padding: 12px;
background: #eee;
}
.item {
float: left;
height: 44px;
width: 100%;
background: #666;
}
</style>
<body>
<div class="block">
<p class="item"></p>
</div>
</body>
此时内部 item 已脱离常规文档流,父元素无法被子元素撑起。若需要父元素包裹住子元素,一是通过常见的 clearfix 方案,二就是同过构造父元素为 BFC,也就是通过大家熟悉的 overflow: hidden,这里涉及到的特性就是 BFC 能包裹住自己的后代浮动元素
<style>
.block {
padding: 12px;
background: #eee;
overflow: hidden;
}
.item {
float: left;
height: 44px;
width: 100%;
background: #666;
}
</style>
<body>
<div class="block">
<p class="item"></p>
</div>
</body>
三、防止被浮动元素覆盖和围绕浮动元素
<style>
.block {
padding: 12px;
background: #eee;
overflow: hidden;
}
.label {
float: left;
height: 44px;
width: 200px;
background: #999;
margin-right: 12px;
}
.content {
height: 68px;
background: #666;
}
</style>
<body>
<div class="block">
<p class="label"></p>
<p class="content"></p>
</div>
</body>
回到最开始的布局问题上了,此时 label 浮动于 content 之上,如果 content 内填充了其他元素,当 content 高度大于 label 一定高度时 content 内元素会被 label 覆盖或文本元素会围绕着 label。如下图,当然不希望右侧地址的第二行会从最左边开始
此时一行代码构造 content 为 BFC,问题便解决了
<style>
.block {
padding: 12px;
background: #eee;
overflow: hidden;
}
.label {
float: left;
height: 44px;
width: 200px;
background: #999;
margin-right: 12px;
}
.content {
height: 68px;
background: #666;
overflow: hidden;
}
</style>
<body>
<div class="block">
<p class="label"></p>
<p class="content"></p>
</div>
</body>
总结
本文对 BFC 稍作梳理,望对代码中那些莫名的 overflow: hidden 的理解有所帮助。上文提到的 overflow: flow-root 可以看下大漠的这篇文章《flow-root》