BFC原理剖析
本文讲了BFC的概念是什么; BFC的约束规则;咋样才能触发生成新的BFC;BFC在布局中的应用:防止margin重叠(塌陷,以最大的为准); 清除内部浮动;自适应两(多)栏布局。
1. BFC是什么?
Block fomatting context = block-level box + Formatting Context
Box:
Box即盒子模型;
- block-level box即块级元素
display属性为block, list-item, table的元素,会生成block-level box;并且参与 block fomatting context;
- inline-level box即行内元素
display 属性为 inline, inline-block, inline-table的元素,会生成inline-level box。并且参与 inline formatting context;
Formatting context
Formatting context是W3C CSS2.1规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系、相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context(简称IFC)。
CSS2.1 中只有BFC和IFC, CSS3中还增加了G(grid)FC和F(flex)FC。
BFC 定义
BFC(Block formatting context)直译为"块级格式化上下文"。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。
2.BFC的生成
上文提到BFC是一块渲染区域,那这块渲染区域到底在哪,它又是有多大,这些由生成BFC的元素决定,CSS2.1中规定满足下列CSS声明之一的元素便会生成BFC。
- 根元素
- float的值不为none
- overflow的值不为visible
- display的值为inline-block、table-cell、table-caption
display:table也认为可以生成BFC,其实这里的主要原因在于Table会默认生成一个匿名的table-cell,正是这个匿名的table-cell生成了BFC
- position的值为absolute或fixed
3. BFC的约束规则
- 内部的Box会在垂直方向上一个接一个的放置
- 垂直方向上的距离由margin决定。(完整的说法是:属于同一个BFC的两个相邻Box的margin会发生重叠(塌陷),与方向无关。)
- 每个元素的左外边距与包含块的左边界相接触(从左向右),即使浮动元素也是如此。(这说明BFC中子元素不会超出他的包含块,而position为absolute的元素可以超出他的包含块边界)
- BFC的区域不会与float的元素区域重叠
- 计算BFC的高度时,浮动子元素也参与计算
- BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面元素,反之亦然
看到以上的几条约束,想想我们学习css时的几条规则
- Block元素会扩展到与父元素同宽,所以block元素会垂直排列
- 垂直方向上的两个相邻DIV的margin会重叠,而水平方向不会(此规则并不完全正确)
- 浮动元素会尽量接近往左上方(或右上方)
- 为父元素设置overflow:hidden或浮动父元素,则会包含浮动元素
4. BFC在布局中的应用
4.1 防止margin重叠(塌陷):
两个相邻Box垂直方向margin重叠
<style>
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
</body>

两个p之间的距离为100px,发送了margin重叠(塌陷),以最大的为准,如果第一个P的margin为80的话,两个P之间的距离还是100,以最大的为准。
根据BFC布局规则第二条:
Box垂直方向的距离由margin决定。属于同一个BFC(上例中是body根元素的BFC)的两个相邻Box的margin会发生重叠
我们可以在p外面包裹一层容器,并触发该容器生成一个新BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。
代码:
<style>
.wrap {
overflow: hidden;// 新的BFC
}
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
</style>
<body>
<p>Haha</p>
<div class="wrap">
<p>Hehe</p>
</div>
</body>

相邻Box水平方向margin重叠
<!doctype HTML>
<html>
<head>
<style type="text/css">
#green {
margin:10px 10px 10px 10px
}
#blue {
margin:10px 10px 10px 10px
}
#red {
margin:10px 10px 10px 10px
}
body {
writing-mode:tb-rl;
}
</style>
</head>
<body>
<div id="green" style="background:lightgreen;height:100px;width:100px;"></div>
<div id="blue" style="background:lightblue;height:100px;width:100px;"></div>
<div id="red" style="background:pink;height:100px;width:100px;"></div>
</body>
</html>
可以看到水平方向的margin发生了重叠。

我们可以给div加个display:inline-block,触每个div容器生成一个BFC。那么三个DIV便不属于同一个BFC(这个只body根元素形成的BFC),就不会发生margin重叠了。

嵌套元素的margin重叠
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title></title>
<style>
html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
#map{
padding:0;
}
.first{
margin:20px;
background:lightgreen;
width:100px;
height:100px;
}
ul{
/*display:inline-block;*/
margin:10px;
background:lightblue;
}
li{
margin:25px;
}
</style>
</head>
<body class="claro">
<div class="first"></div>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>
</html>
此时div与ul之间的垂直距离,取div、ul、li三者之间的最大外边距。

要阻止嵌套元素的margin重叠,只需让ul生成BFC即可(将上例中的注释去掉),这样div、ul、li之间便不会发生重叠现象。

而li位于同一BFC内所以仍然存在重叠现象。

给li设置line-block重新生成一个bfc就不存在重叠现象了。

需要注意的是:
如果为ul设置了border或padding,那元素的margin便会被包含在父元素的盒式模型内,不会与外部div重叠。
《CSS权威指南》中提到块级正常流元素的高度设置为auto,而且只有块级子元素,其默认高度将是从最高块级子元素的外边框边界到最低块级子元素外边框边界之间的距离。如果块级元素右上内边距或下内边距,或者有上边框或下边框,其高度是从其最高子元素的上外边距边界到其最低子元素的下外边距边界之间的距离。
4.2 清除内部浮动
<style>
.par {
border: 5px solid #fcc;
width: 300px;
}
.child {
border: 5px solid #f66;
width:100px;
height: 100px;
float: left;
}
</style>
<body>
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
</body>
页面:
根据BFC布局规则第六条:
计算BFC的高度时,浮动元素也参与计算
为达到清除内部浮动,我们可以触发par生成BFC,那么par在计算高度时,par内部的浮动元素child也会参与计算。
.par {
overflow: hidden;
}
4.3 自适应多栏布局的
4.3.1 自适应两栏布局
<style>
body {
width: 300px;
position: relative;
}
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
background: #fcc;
}
</style>
<body>
<div class="aside"></div>
<div class="main"></div>
</body>
根据BFC布局规则第3条:
每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
因此,虽然存在浮动的元素aslide,但main的左边依然会与包含块的左边相接触。
根据BFC布局规则第四条:
BFC的区域不会与float box重叠。
我们可以通过通过触发main生成BFC, 来实现自适应两栏布局。
.main {
overflow: hidden;
}
当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。效果如下:
4.3.2 自适应两栏布局
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<!--The viewport meta tag is used to improve the presentation and behavior of the samples
on iOS devices-->
<meta name="viewport" content="initial-scale=1, maximum-scale=1,user-scalable=no"/>
<title></title>
<style>
html, body { height: 100%; width: 100%; margin: 0; padding: 0; }
.left{
background:pink;
float: left;
width:180px;
}
.center{
background:lightyellow;
overflow:hidden;
}
.right{
background: lightblue;
width:180px;
float:right;
}
</style>
</head>
<body class="claro">
<div class="container">
<div class="left">
<pre>
.left{
background:pink;
float: left;
width:180px;
}
</pre>
</div>
<div class="right">
<pre>
.right{
background:lightblue;
width:180px;
float:right;
}
</pre>
</div>
<div class="center">
<pre>
.center{
background:lightyellow;
overflow:hidden;
height:116px;
}
</pre>
</div>
</div>
</html>
这种布局的特点在于左右两栏宽度固定,中间栏可以根据浏览器宽度自适应。
4. 总结
其实以上的几个例子都体现了BFC布局规则第五条:
BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
因为BFC内部的元素和外部的元素绝对不会互相影响,因此,
当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠。 同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。 避免margin重叠也是这样的一个道理。
BFC原理剖析的更多相关文章
- <HTML/CSS>BFC原理剖析
本文讲了BFC的概念是什么: BFC的约束规则:咋样才能触发生成新的BFC:BFC在布局中的应用:防止margin重叠(塌陷,以最大的为准): 清除内部浮动:自适应两(多)栏布局. 1. BFC是什么 ...
- 前端里神奇的BFC 原理剖析
以前在做自适应两栏布局的时候别人口中听到bfc这个词,于是看了各种关于bfc的文章,发现梦想天空介绍的不错,今天就在他的基础上润色一下. 一.BFC是什么? 在解释 BFC 是什么之前,需要先介绍 B ...
- CSS—BFC原理解析与应用
我们在很多地方都见过BFC这个词,或许能够知道大概意思,但是有时候它的具体原理以及作用会记得很模糊,下面就对BFC这个概念深入学习下. 块级格式化上下文(Block Formatting Contex ...
- BFC 原理
BFC:Block-level box + Forating + Context; ------->块元素 决定其子元素如何定位, ...
- CSS 盒模型、解决方案、BFC 原理讲解--摘抄
PS:内容比较基础,目的只是覆盖面试知识点,大佬可以 history.back(-1) W3C 标准盒模型 & IE 怪异盒模型 页面上显示的每个元素(包括内联元素)都可以看作一个盒子,即盒模 ...
- 10分钟理解BFC原理
10 分钟理解 BFC 原理 一.常见定位方案 在讲 BFC 之前,我们先来了解一下常见的定位方案,定位方案是控制元素的布局,有三种常见方案: 普通流 (normal flow) 在普通流中,元素按照 ...
- SpringMVC的url-pattern配置及原理剖析
SpringMVC的url-pattern配置及原理剖析 xml里面配置标签: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc./ ...
- ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件)
ASP.NET Core 运行原理剖析2:Startup 和 Middleware(中间件) Startup Class 1.Startup Constructor(构造函数) 2.Configure ...
- ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行
ASP.NET Core 运行原理剖析1:初始化WebApp模版并运行 核心框架 ASP.NET Core APP 创建与运行 总结 之前两篇文章简析.NET Core 以及与 .NET Framew ...
随机推荐
- Java实现Base64加密
阅读本文约“2.5分钟” Java加解密系列,介绍Java加密解密的基础知识,并使用Base64算法实现加解密. 对于加密在企业中是非常常见的,就如邮件的传输,每个企业都会有自己设置安全方式,设置加密 ...
- 28-30 js 文本全选
要点:使用select(); 上代码: if (e.keyCode === 27){ document.getElementById('input').select() } //当点击键盘esc键时候 ...
- vue2 切换路由时 页面滚动到顶部 用游览器返回时 记住上页的位置
官方用例:https://router.vuejs.org/zh-cn/advanced/scroll-behavior.html import Vue from 'vue' import Route ...
- 04-HTML-图片标签
<html> <head> <title>图片标签学习</title> <meta charset="utf-8"/> ...
- 花十分钟,让你变成AI产品经理
花十分钟,让你变成AI产品经理 https://www.jianshu.com/p/eba6a1ca98a4 先说一下你阅读本文可以得到什么.你能得到AI的理论知识框架:你能学习到如何成为一个AI产品 ...
- 23.Odoo产品分析 (三) – 人力资源板块(4) – 招聘流程(1)
查看Odoo产品分析系列--目录 安装招聘流程模块: 可以看到我们在前面的章节中设置的"生产经理"岗位,和其他的看板视图一样,每一个岗位板块提供了各种便捷的操作入口和颜色设置. ...
- Deep Learning - 2 反向传播
深度神经网络的学习基于两个关键技术: Stochastic Gradient Descent Backpropagation 利用 SGD 算法学习 Weights 和 Biases,利用 Backp ...
- Last Day in Autodesk
今天是我的最后一天在Autodesk上海了,以后将不再折腾那么大的软件了,还是回到CG开发中捣鼓短小精悍的东西——我还将继续整理开源CG生产工具. Today is my last day in Au ...
- Android JNI中C调用Java方法
背景需求 我们需要在JNI的C代码调用Java代码.实现原理:使用JNI提供的反射借口来反射得到Java方法,进行调用. JNI关键方法讲解. 1. 在同一个类中,调用其他方法 JNIEXPORT v ...
- Android Studio多渠道打包(一)
1. 多渠道的概念 APP发布到不同的应用平台,监测用户是从哪个平台安装的. 2. 为什么要多渠道打包 统计用户安装APP来源 批量修改生成的apk文件名 可更改包名 生成不同应用名称或图标 3.多渠 ...