常常问到的 BFC 和 IFC 是什么?

什么是BFC?什么做用?

Block Formatting Contextcss

块盒子布局发生的区域,浮动元素和其余元素交互的区域html

浮动定位和清除浮动的时候只会应用于同一个BFC内的元素。浮动不会影响其余BFC中元素的布局,而清除浮动只能清除同一BFC中在它前面的元素的浮动git

外边距的折叠也只会发生在同一BFC中的块级元素之间。能够建立新的BFC来消除外边距的折叠问题。github

常见的定位布局方案有,普通流,浮动和绝对定位。浏览器

BFC 是一块渲染区域,有一套渲染定位规则。决定子元素定位其余元素的关系和相互做用,是属于普通流的。具备 BFC 特性的元素能够看做是隔离了的独立容器,容器里面的元素不会在布局上影响到外面的元素,而且 BFC 具备普通容器所没有的一些特性。ide

其实也不是什么新鲜东西,可能都在用但不知道这个概念。布局


案例1:使浮动元素和周围内容等高

对于如下代码:flex

<style>
  .box {
    background-color: rgb(224, 206, 247);
    border: 5px solid rebeccapurple;
    /* overflow: auto; */
    /* display: flow-root; */
  }
  .float {
    float: left;
    width: 400px;
    height: 150px;
    background-color: white;
    border: 1px solid black;
    padding: 10px;
  }
</style>
<div>
  <div class="box">
    <div class="float">I am a floated box!</div>
    <p>I am content inside the container.</p>
  </div>
</div>

显示的效果以下:ui

由于浮动盒子脱离了文档流。浮动的div元素更大,就穿出了边框。this

通常是须要将盒子和浮动元素作成等高的,即浮动元素应该包含在box内部,要达到这个效果,能够这样:

  1. 使用display: flow-root

    一个新的display属性值,能够建立无反作用的BFC。在父级元素中使用display: flow-root就能够建立新的BFC。

    能够理解为和建立根元素同样,建立一个文档流的上下文

  2. 使用overflow:auto

    只要设置overflow为一个非visible的值就能够。使用overflow建立一个新的BFC,overflow会告诉浏览器如何处理超出部分的内容。

    可是若是只是用来建立BFC的话,可能引起其余状况。


案例2: 清除外部浮动

对于如下代码:

<style>
  section {
    height: 150px;
  }
  .box {
    background-color: rgb(224, 206, 247);
    border: 5px solid rebeccapurple;
  }
  .box[style] {
    background-color: aliceblue;
    border: 5px solid steelblue;
  }
  .float {
    float: left;
    overflow: hidden; /* required by resize:both */
    resize: both;
    margin-right: 25px;
    width: 200px;
    height: 100px;
    background-color: rgba(255, 255, 255, 0.75);
    border: 1px solid black;
    padding: 10px;
  }
</style>


<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="box" style="display:flow-root"><p>	   	  	
    <code>display:flow-root</code><p>
  </div>
</section>

这里须要关注的是float元素上的margin-right这个属性。

上面的两个元素之间,margin-right 没有生效。可是对box添加display:flow-root属性以后,margin-right 属性就生效了,左边的元素缩放的时候始终都保持有25px的距离。也就是display:flow-root对同级的外部元素的浮动也清除了

若是对HTML部分写成这样:

<section>
  <div class="float">Try to resize this outer float</div>
  <div class="float">Try to resize this outer float</div>
  <div class="box"><p>Normal</p></div>
</section>
<section>
  <div class="float">Try to resize this outer float</div>
  <div class="float">Try to resize this outer float</div>
  <div class="box" style="display: flow-root">
    <p><code>display:flow-root</code></p>
    <p>xx</p>
  </div>
</section>

消除同级元素的float, 显示出 margin-right 的效果就更明显了。

须要注意的是:清除同一BFC中的浮动,只能清除在它前面元素的浮动。


案例3: 外边距塌陷问题

对于以下代码:

<style>
  .blue,
  .red-inner {
    height: 50px;
    margin: 50px 0;
    background: blue;
  }

  .red-outer {
    /* display: flow-root; */
    /* overflow: hidden; */
    background: red;
  }
</style>

<body>
  <div class="blue"></div>
  <div class="red-outer">
    <div class="red-inner">red inner</div>
  </div>
</body>

显示的效果以下:

能够看到,对red-inner的margin无法撑起盒子,两个蓝色盒子之间的距离是50px.

使用display: flow-root;

两个蓝色盒子就距离100px了,并且margin也彻底显示了出来。


建立BFC的方法

使用这些BFC的特性,须要建立出BFC:

  • 根元素(<html>)
  • 浮动元素(元素的 float 不是 none
  • 绝对定位元素(元素的 positionabsolutefixed
  • 行内块元素(元素的 displayinline-block
  • 表格单元格(元素的 displaytable-cell,HTML表格单元格默认为该值)
  • 表格标题(元素的 displaytable-caption,HTML表格标题默认为该值)
  • 匿名表格单元格元素(元素的 displaytable、``table-rowtable-row-group、``table-header-group、``table-footer-group(分别是HTML table、row、tbody、thead、tfoot 的默认属性)或 inline-table
  • overflow 计算值(Computed)不为 visible 的块元素
  • display 值为 flow-root 的元素
  • contain 值为 layoutcontent 或 paint 的元素
  • 弹性元素(displayflexinline-flex 元素的直接子元素)
  • 网格元素(displaygridinline-grid 元素的直接子元素)
  • 多列容器(元素的 column-countcolumn-width (en-US) 不为 auto,包括 ``column-count1
  • column-spanall 的元素始终会建立一个新的BFC,即便该元素没有包裹在一个多列容器中(标准变动Chrome bug

什么又是 IFC?

相对于块级格式化上下文,还有行内格式化上下文,Inline formatting context

对于IFC,行内框一个接一个地排列,排列顺序和书写方向一致。

  • 水平书写模式,行内框从左边开始水平排列
  • 垂直书写模式,行内框从顶部开始水平排列

一个行内框在被分割到多行中的时候,margin,border以及padding的设定不会在断裂处生效(边框跨行连续,不会产生两块border)

Margin,border和padding的设置在行方向上生效。

垂直方向上对齐

垂直方向上的位置主要是用vertical-align

<style>
  .horizontal {
    writing-mode: horizontal-tb;
   }

  .vertical {
    writing-mode: vertical-rl;
   }
	span {
    font-size: 200%;
    /* vertical-align: top; */
    vertical-align: bottom;
   }
</style>    

<div class="example horizontal">
      Before that night—<span>a memorable night</span>, as it was to prove—hundreds of millions of
      people had watched the rising smoke-wreaths of their fires without drawing any special
      inspiration from the fact.”
</div>

显示效果:

而若是将vertical-align: bottom设置为top,效果则是顶部对齐

须要注意的是,若是文字方向是垂直书写模式的话,对齐方式不变,但实际上应该是左右对齐,与vertical-align的字面意思稍有出入。在vertical-align:top再加上writing-mode: vertical-rl

水平方向上对齐

行内元素在水平方向上的位置主要是用text-align

<style>
   .horizontal {
    writing-mode: horizontal-tb;
   }

  .vertical {
    writing-mode: vertical-rl;
   }
	.example {
    text-align: center;
  }
</style>

<div class="example horizontal" style="border: 1px solid">One Two Three</div>
<div class="example vertical">One Two Three</div>

显示效果:


参考: