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. 图标字体 VS 雪碧图——图标字体应用实践

    本文介绍使用图标字体和SVG取代雪碧图的方法.雪碧图是很多网站经常用到的一种技术,但是它有缺点:高清屏会模糊.无法动态变化如hover时候反色.而使用图标字体可以完美解决上述问题,同时具备兼容性好,生 ...

  2. C#开发微信门户及应用(20)-微信企业号的菜单管理

    前面几篇陆续介绍了很多微信企业号的相关操作,企业号和公众号一样都可以自定义菜单,因此他们也可以通过API进行菜单的创建.获取列表.删除的操作,因此本篇继续探讨这个主体,介绍企业号的菜单管理操作. 菜单 ...

  3. C++ map的基本操作和使用

    原文地址:http://blog.sina.com.cn/s/blog_61533c9b0100fa7w.html Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可 ...

  4. java转换 HTML字符实体,java特殊字符转义字符串

    为什么要用转义字符串? HTML中<,>,&等有特殊含义(<,>,用于链接签,&用于转义),不能直接使用.这些符号是不显示在我们最终看到的网页里的,那如果我们希 ...

  5. Mockjs,模拟数据生成器

    (推荐使用)Mock.js是一款模拟数据生成器,旨在帮助前端攻城师独立于后端进行开发,帮助编写单元测试. 提供了以下模拟功能: 1. 根据数据模板生成模拟数据. 2. 模拟Ajax请求,生成并返回模拟 ...

  6. 【转】iOS UIApplication详解

    1.状态栏UIStateBar的设置是在UIApplication里面设置的,它包含4中风格 2. - (void)beginIgnoringInteractionEvents; (void)endI ...

  7. Android Weekly Notes Issue #228

    Android Weekly Issue #228 October 23rd, 2016 Android Weekly Issue #228 本期内容包括: Android 7.1的App Short ...

  8. centos直接yum安装nginx

    Ubuntu下安装nginx,直接apt-get install nginx就行了,很方便. 但是今天装了CentOS6.2,直接yum install nginx不行,要先处理下源,下面是安装完整流 ...

  9. android MD5加密

    public class MD5Uutils {    //MD5加密,32位    public static String MD5(String str) {        MessageDige ...

  10. web.xml 配置中classpath: 与classpath*:的区别

    首先 classpath是指 WEB-INF文件夹下的classes目录 解释classes含义: 1.存放各种资源配置文件 eg.init.properties log4j.properties s ...