BFC是CSS中一个非常重要的概念,经常用来清除浮动以及处理外边距折叠,但BFC到底是个什么东西却很难准确的表达清楚,国内的相关技术文档基本都不全面,本文的目的就是对BFC的方方面面做个整理,当然未必会一次性整理到位,后面如果发现有遗留错误的会继续补充。
 
什么是BFC?
BFC(Block formatting context)译为"块格式化上下文",是一个独立的渲染区域,规定了内部的子元素如何布局,并且与这个区域外部的关系。
 
什么情况下会产生BFC?
a、根元素(注意:这里必须手动设置,默认不触发BFC)
b、float属性不为none
c、position为absolute或fixed
d、display为inline-block, table-cell, table-caption, flex, inline-flex
e、overflow不为visible(除非该值已经被传播到视口)
 
BFC布局规则是怎样的?
a、内部的Box会在垂直方向,一个接一个地放置。
b、Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
c、每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
d、BFC的区域不会与float box重叠。
e、BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
d、计算BFC的高度时,浮动元素也参与计算
相关解读:
a、并不是只有块元素才会生成BFC,任何元素只要符合条件即可生成BFC
 
BFC应用及原理解析
 
1、自适应两栏布局
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
}
.main {
height: 200px;
background: #fcc;
}
<div class="aside"></div>
<div class="main"></div>

效果图:

关于效果图的解释,有资料用BFC布局规则c来解释:
 
  “每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。”
 
其实这样解释不完全正确,第三条布局生效的前提是父元素生成了BFC,从代码中可以看出他们的父元素时body,又从“根元素”可以生成BFC中似乎可以肯定应用这条布局规则是正确的,但有一点需要注意这里的“根元素”不是body,而是html,至于为什么,下一面再讲。
 
虽然上面这个效果图不可以完全用BFC来解释,但实现两栏自适应布局确可以完全用BFC来实现,根据规则d说明:
 
  “BFC的区域不会与float box重叠”
 
我们可以通过通过触发main生成BFC, 来实现自适应两栏布局。
main {
overflow: hidden;
}
当触发main生成BFC后,这个新的BFC不会与浮动的aside重叠。因此会根据包含块的宽度,和aside的宽度,自动变窄。效果如下:
 
 
2、清除浮动
 .par {
border: 5px solid #fcc;
width: 300px;
} .child {
border: 5px solid #f66;
width:100px;
height: 100px;
float: left;
<div class="par">
<div class="child"></div>
<div class="child"></div>
</div>
效果图:
根据BFC布局规则d:
 
  “计算BFC的高度时,浮动元素也参与计算”
 
为达到清除内部浮动,我们可以触发par生成BFC,那么par在计算高度时,par内部的浮动元素child也会参与计算。
代码:
.par {
overflow: hidden;
}
效果图:
 
3、防止外边距折叠
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
<p>Haha</p>
<p>Hehe</p>
效果图:
从图中可以看出,两个p元素的外边距发生了重叠,有资料用规则d来解释:
 
  “Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠”
 
这条规则生效的前提是根元素生成了BFC,但上文已经说过body元素默认是不生成BFC的,既然这样那又该如何解释呢?
 
根据W3C规范box model一节里Collapsing margins部分的说明,基本的意思是比邻元素的边距总是折叠,除了以下几种情况:
1、Margins of the root element's box do not collapse.(根元素不折叠)
2、If the top and bottom margins of an element with clearance are adjoining, its margins collapse with the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block.(有间隙不折叠)
 
1、Margins between a floated box and any other box do not collapse (not even between a float and its in-flow children).(浮动不折叠)
2、Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.(创建BFC与子不折叠)
3、Margins of absolutely positioned boxes do not collapse (not even with their in-flow children).
Margins of inline-block boxes do not collapse (not even with their in-flow children).(positioned 不折叠)
4、Margins of inline-block boxes do not collapse (not even with their in-flow children).(inline-box 不折叠)
5、The bottom margin of an in-flow block-level element always collapses with the top margin of its next in-flow block-level sibling, unless that sibling has clearance.(兄弟有间隙不折叠)
6、The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.(父子间有padding 和 border 不折叠)
 
由此可见两个p元素发生折叠并不是因为BFC的缘故,虽然如此,我们依旧可以通过BFC的方法来解决折叠问题
我们可以在p外面包裹一层容器,并触发该容器生成一个BFC。那么两个P便不属于同一个BFC,就不会发生margin重叠了。
代码:
.wrap {
overflow: hidden;
}
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
}
<p>Haha</p>
<div class="wrap">
<p>Hehe</p>
</div>
效果图:
 
被忽略的部分
根元素产生BFC,这里的根元素默认不触发BFC,必须额外设置,很多资料上都未提及这个问题,看看下面的代码你就知道了
html,body{ margin:0px; }
html{ background-color: white; }
body{ background-color: green; }
.box{ width: 300px; height: 200px; margin-top: 100px; background-color: gray; }
<div class="box"></div>
效果图:
很明显这里的根元素并未能阻止外边距折叠,如果这个还不是很明显的话再来看看下一个
html,body{ margin:0px; }
html{ background-color: white; }
body{ background-color: green; }
.box{ width: 300px; height: 200px; background-color: gray; float: left; }
<div class="box"></div>
效果图:
根据BFC规则d
 
  “计算BFC的高度时,浮动元素也参与计算”
 
body的高度不应该是200px吗,怎么会是0
 
根元素什么情况下才会产生BFC呢?
经过测试发现,只有同时给html,body都加上overflow : hidden,才能触发BFC,又或者给body加上display : inline-block,display : table,position : absolute也可以触发BFC
方法一:
html,body{ margin:0px; }
html{ background-color: white; overflow: hidden;}
body{ background-color: green; overflow: hidden; }
.box{ width: 300px; height: 200px; background-color: gray; float: left; }

方法二:

html,body{ margin:0px; }
html{ background-color: white;}
body{ background-color: green; display:table/inline-block; /*position : absolute;*/ }
.box{ width: 300px; height: 200px; background-color: gray; float: left; }
 
为什么会这样呢,不是根元素会产生BFC吗?来看看规范是怎么说的
“Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.”
overflow:visible以外的块级元素将创建BFC,除非该值已经扩散到了视口。(大部分中文资料都忽略了这点)
 
再来看看overflow相关的标准:
UAs must apply the 'overflow' property set on the root element to the viewport.
1、When the root element is an HTML "HTML" element or an XHTML "html" element, and that element has an HTML "BODY" element or an XHTML "body" element as a child, user agents must instead apply the 'overflow' property from the first such child element to the viewport, if the value on the root element is 'visible'.
2、The 'visible' value when used for the viewport must be interpreted as 'auto'.
3、The element from which the value is propagated must have a used value for 'overflow' of 'visible'.
 
总结一下大概是这几点意思:
1、UA需要将root元素上的overflow属性置于视口之上;
2、overflow扩散行为:当root元素是html元素且overflow为visible,而且html元素有body作为其子元素,UA则需要将第一个body之上的overflow属性应用于视口;
3、用于视口的overflow: visible将被解析为overflow: auto
4、overflow扩散行为将导致body的使用值为overflow: visible
 
根据这几个规范,就可以解释根元素产生BFC了:
1、给body加上overflow:hidden,无法触发BFC创建。
解释:本用例中body {overflow:hidden},body的overflow:hidden被应用于视口,body的最终使用值为overflow:visible,因此body没有创建BFC。
2、给body和html同时加上overflow:hidden,成功触发BFC创建。
解释:本用例中body, html{overflow:hidden},html的overflow:hidden被用于视口,body的overflow计算值是hidden,因此创建了BFC。
3、给body加上display:table、display:inline-block、position:absolute,成功触发BFC创建。
解释:这些属性都导致body正常创建了BFC。
 
总结:
BFC大部分特性都可以用一句话来概括:
 
  “BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。”
 
因为BFC内部的元素和外部的元素绝对不会互相影响,因此, 当BFC外部存在浮动时,它不应该影响BFC内部Box的布局,BFC会通过变窄,而不与浮动有重叠。同样的,当BFC内部有浮动时,为了不影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。
 
本篇中反复提到外边距折叠的问题,这也是一个比较大的问题,不仅仅涉及到BFC,有空再出一篇文章。
 
参考资料:
https://www.w3.org/TR/CSS2/box.html#collapsing-margins
https://segmentfault.com/q/1010000002645174
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://www.cnblogs.com/pigtail/archive/2013/01/23/2871627.html
https://www.zhihu.com/question/35375980/answer/62492644
https://www.zhihu.com/question/35030317/answer/60872188

神奇的BFC以及被忽略的东西的更多相关文章

  1. 神奇的BFC

    BFC是什么? 块格式化上下文(Block/box Formatting Context,BFC) 是Web页面的可视CSS渲染的一部分,是块盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域 ...

  2. 前端里神奇的BFC 原理剖析

    以前在做自适应两栏布局的时候别人口中听到bfc这个词,于是看了各种关于bfc的文章,发现梦想天空介绍的不错,今天就在他的基础上润色一下. 一.BFC是什么? 在解释 BFC 是什么之前,需要先介绍 B ...

  3. JAVA 容易忽略的东西

    Java中的取余会出现负数.用Math.floorMod()方法可以掰正,但是也仅限被除数是负数的情况,如果除数是负数,这个没用. 和C不一样,Java中的字符串是不可变字符串,不能修改Java字符串 ...

  4. margin塌陷与BFC总结

    只给出关键点,具体效果不做太多示范,真正的东西只有自己试了才能记住 BFC BFC触发: 1.position:absolute/fixed 2.float:left/right 3.display: ...

  5. SVN的忽略和只读使用方法学习记录

    前言,先扯几句.最近学了GIT,虽然很肤浅,但是也算是用上了分布式版本管理控制系统.Linus很牛,他也很厌烦SVN,而我看这些都是工具,是否拿来使用主要看是否顺手.我赞同分布式版本管理控制,它有诸多 ...

  6. iOS深入学习(UITableView:系列1-最基本的东西)

    这是UITableView博客系列的第一篇,使用xib和arc编码,主要讲解一些UITableView使用过程中简单的.但是又容易被忽略的东西,而且我会告诉读者,怎样在使用了之后就再也不会忘记. 操作 ...

  7. P1679 神奇的四次方数

    P1679 神奇的四次方数用一些什么东西组成一个什么东西,要求什么东西最优,这时候要考虑背包,不过要分析清楚是什么类型的背包.这题显然是个完全背包. #include<iostream> ...

  8. 浅谈对BFC的认识,以及用bfc解决浮动问题

    我们在前端的学习过程中常常会遇到BFC,用BFC来解决一些margin塌陷.margin合并清理浮动流的问题 那么问题来了,我们所说的BFC到底是个什么东西呢: 什么是BFC BFC(Block Fo ...

  9. PJAX的实现与应用

    一.前言 web发展经历了一个漫长的周期,最开始很多人认为Javascript这们语言是前端开发的累赘,是个鸡肋,那个时候人们还享受着从一个a链接蹦 到另一个页面的web神奇魔术.后来随着JavaSc ...

随机推荐

  1. 前端打包构建工具gulp快速入门

    因为之前一直有人给我推荐gulp,说他这里好哪里好的.实际上对我来说够用就行.grunt熟悉以后实际上他的配置也不难,说到效率的话确实是个问题,尤其项目大了以后,目前位置遇到的项目都还可以忍受.不过不 ...

  2. 一种开发模式:ajax + ashx + UserControl

    一.ajax+ashx模式的缺点     在web开发过程中,为了提高网站的用户体验,或多或少都会用到ajax技术,甚至有的网站全部采用ajax来实现,大量使用ajax在增强用户体验的同时会带来一些负 ...

  3. Linux零起点之进程管理----c语言编程

    进程 (Process)是指操作系统中被加载到内存中的.正在运行的应用程序实例.进程是系统资源分配的基本单元,在其生命周期内会使用系统中的各种资源.进程主要由程序.数据以及进程控制快(PCB)3个部分 ...

  4. Base-64 字符数组或字符串的长度无效等问题解决方案

    项目特殊需要,调用ActiveX三维控件进行控件某一特殊部位的截图操作,这个截图保存由ActiveX控件控制保存到本地是没问题的,现在需要将这个截图上传到服务器,多人共享,就牵扯到需要读取本地文件…… ...

  5. Dapper-据说stackoverflow使用的orm

    using System; using System.Collections.Generic; using System.Data; using System.Data.SqlClient; usin ...

  6. SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.

    相信很多人进行数据存储时,会遇上如标题的异常错误. 其实也不算上一个错误. 当你的程序中有宣告一个字段的数据类型为DateTime时,但你又没有赋值给它,就进行存储时,它就会得到这样一个结果. 看看下 ...

  7. dbutils基本使用

    dbutils的查询,主要用到的是query方法,增加,修改和删除都是update方法,update方法就不讲了 只要创建ResultSetHandler接口不同的实现类对象就可以得到想要的查询结果, ...

  8. Sublime text 2/3 中 Package Control 的安装与使用方法

    Package Control 插件是一个方便 Sublime text 管理插件的插件,但因为 Sublime Text 3 更新了 Python 的函数,API不同了,导致基于 Python 开发 ...

  9. 你知道JavaScript中的结果值是什么吗?

    你知道JavaScript中的每条语句.甚至表达式都有一个结果值吗? 当你在浏览器中测试代码时,经常会在控制台的输出结果的最后面多出一条,大部分为undefined,这个undefined就是一个结果 ...

  10. UIScrollView的封装

    UIScrollView的封装 效果 特点 1.用法简单,尺寸大小,随意设置位置 2.可以有多个数据源的数据,可以定制不通的界面(如同上图,一个有文字,一个没有文字) 3.能够实现点击事件 用法 1. ...