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. C标准头文件<errno.h>

    声明了错误处理相关的宏 errno errno即error number,在程序启动时被设为0,当某个库函数运行出现错误的时候,会将相应的能表达错误类型的数字赋值给这个左值,这些数字往往有相应的宏来表 ...

  2. instanceof 运算符

    java中的instanceof=======>二元运算符 用法: result = object instanceof class 参数: result 是boolean类型 object 是 ...

  3. CSS3 @font-face的使用

    首先我们一起来看看@font-face的语法规则: @font-face { font-family: <YourWebFontName>; src: <source> [&l ...

  4. 自助式BI为何能取代传统BI,逐渐占据商业智能市场?

    前言:未来的时代将由数据勾画,未来的BI将是自助BI的时代 随着数据爆发式增长,像ERP.OA.CRM等系统在企业运用的越来越多.这些系统的使用必然会产生很多的数据,比如在产品加工设计测试维护过程中产 ...

  5. HotApp小程序统计,第一个专业的微信第三方小程序统计工具

    1.什么是HotApp小程序统计 HotApp小程序统计是第一个微信第三方小程序统计工具,就像做android 和 ios开发的人知道友盟统计一样,小程序也需要有个统计工具. 通过这个工具,可以知道小 ...

  6. React Native class 后面的命名首字母需要大写

    React Native class 后面的命名首字母需要大写 否则会报Expeted a component class,got [object Object].

  7. AndroidProjects个人项目归纳

    AndroidProjects 个人总结归纳-目录大纲 Data Binding框架MVVM BaseView CollapseView 更新中... 项目地址:https://github.com/ ...

  8. 安装redis以windows服务形式

    安装redis以windows服务形式 安装redis以windows服务形式 redis windows windows 服务 以前跑redis,老是要开一个命令行窗口,一旦关闭,redis服务就挂 ...

  9. java编码原理,java编码和解码问题

    java的编码方式原理 java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关 . 在JAVA源文件-->JAVAC-->Class-->Java--& ...

  10. Ext JS - 问答

    Ext JS - 问答 在下面你将可以找到关于Ext JS 的最常见问题的答复.如果没有找到您所需的答复,请访问 Ext JS 论坛或者提交一个支持申请. 如果你确信你的问题可以对本页有补充,请让我们 ...