CSS格式化上下文

2,209 阅读6分钟

FC(formatting context)是CSS规范中的一个概念,指的是页面布局中的一块渲染区域,在这块区域内有一套渲染规则,用来决定其子元素如何布局,以及与其他元素之间的关系和相互作用。普通流中的每个盒子都会参与到一个FC中,可能是BFC,也可能是IFC,但不可能即是BFC又是IFC。

CSS2定义了两种FC类型:BFC(Block formatting context)和IFC(Inline formatting context)。

CSS3中又新增了两种:GFC(grid formatting context)和FFC(flex formatting context)。

BFC 块级格式化上下文

只有block-level元素参与的渲染区域,BFC规定并管理内部block-level元素的布局方式。

布局规则

  1. BFC内的盒子均沿着垂直方向逐个排列。

  2. BFC内盒子之间的垂直距离由margin属性决定,垂直方向上直接相邻的margin会发生塌陷/合并(不存在padding和border),并且以最大的margin值作为最终的margin值。

    父子元素

    <div style="display:inline-block; border: 1px dotted black;">
        <div style="margin: 10px;">
        <div style="margin: 15px; width: 100px; height: 50px; background-color: blue;"></div>
        </div>
    </div>
    

    图1
    图2
    橙色框均表示元素的外边距。图1展示的是子元素的外边距,图2则是父元素的。 可见,父子元素相邻的垂直外边距出现合并且最终使用了较大的外边距,而水平外边距不存在重叠问题。

    兄弟元素

    <div style="border:1px solid black; width: 100px;">
        <div style="margin: 10px; height: 50px; background-color: blue;"></div>
        <div style="margin: 5px; height: 20px; background-color: blue;"></div>
    </div>
    

    兄弟元素外边距合并
    外边距相同的兄弟元素,相邻的垂直外边距发生了合并。图中兄弟元素的垂直间距不是10px+10px,而是max(10px, 10px)。

    空盒子

    <div style="border: 1px solid black; width: 200px;">
    	<div style="margin: 10px;"></div>
    </div>
    

    空盒子的垂直margin直接相邻,也会发生合并。

  3. BFC内盒子的左外边缘都会接触包含块的左边缘(如果从右到左进行排版,那么右边发生接触),即使存在浮动盒子也是如此。

  4. BFC的内容不会与浮动元素发生重叠,且浮动元素也会参与BFC的高度计算。

  5. BFC是一个隔离的独立容器,容器里面的子元素不会影响外面的元素,反过来也一样。

如何触发BFC

  1. 根元素<html>
  2. 浮动元素(float不为none)
  3. 绝对定位元素(position为absolute或fixed)
  4. overflow不为visible的块元素
  5. 内联块元素、表格单元格、表格标题(display为inline-block/table-cell/table-caption)
  6. 弹性元素(display为flex或inline-flex元素的直接子元素)

满足上述任一条件即可在其内部产生BFC。(更多详细的可参考MDN文档)

作用

防止外边距合并

根据BFC布局规则: 同一个BFC内相邻盒子之间的外边距会发生合并。

创建新的BFC,不属于同一个BFC的盒子不会出现外边距合并。

<div style="border:1px solid black; width: 100px;">
    <div style="margin: 10px; height: 50px; background-color: blue;"></div>
    <!--创建新的BFC-->
    <div style="overflow: hidden;">
        <div style="margin: 10px; height: 20px; background-color: blue;"></div>
    </div>
</div>

清除内部浮动

根据BFC布局规则: BFC内浮动元素也会参与BFC的高度计算。

<div style="border: 2px solid black; width: 200px;">
    <div style="float: left; width: 50px; height: 150px; background-color: red;">浮动</div>
    <div style="height: 100px; background-color: blue;"></div>
</div>

在包含块内存在一个浮动元素。浮动元素脱离文档流存在,因此包含块没有办法“掌握”整个浮动元素。一旦浮动元素的高度大于它旁边的元素,那它会穿透包含块。

通过设置overflow: hidden或display: inline-block等方式,在包含浮动元素的容器内创建BFC。BFC在计算高度的时候会将识别并计算浮动元素,效果相当于清除内部浮动。

<!--overflow: hidden-->
<div style="overflow: hidden;border: 2px solid black; width: 200px;">
    <div style="float: left; width: 50px; height: 150px; background-color: red;">浮动</div>
    <div style="height: 100px; background-color: blue;"></div>
</div>

自适应两栏布局

根据BFC的布局规则: BFC的内容不会与浮动元素发生重叠。

<div style="overflow: hidden;border: 2px solid black; width: 200px;">
    <div style="float: left; width: 50px; height: 100px; background-color: red;">浮动</div>
    <div style="height: 100px; background-color: blue;">这是一段内容。</div>
</div>

BFC的内容环绕在浮动元素周围,不会与其发生重叠,可以通过这种方式实现自适应两栏/多栏的布局。

IFC 内联格式化上下文

只有inline-level元素参与的渲染区域,IFC规定并管理inline-level元素的布局方式。

布局规则

  1. 盒子沿着水平方向逐个排列。
  2. 只会计算盒子水平方向上的margin、border和padding,而不会计算垂直方向上的。
  3. 在垂直方向上,盒子有多种对齐方式(vertical-align):可以top对齐,或者bottom对齐,也可以通过文本基线(baseline)对齐。
  4. 能把一行的盒子完全包含进去的方形区域,被称为行框(line box)
  5. 行框的高度由CSS行高计算规则确定,而且同个IFC内的行框高度一般不同(行框内最高元素的高度可能不同)。
  6. 行框通常是左右边紧贴包含块,但会因为浮动元素的存在而发生变化。行框的宽由包含块和存在的浮动元素决定,浮动元素可能导致行框宽度变小。如果行框内所有盒子的总宽度小于行框的宽度,那行框内盒子的水平分布方式由text-align属性决定(如果这个属性是justify,那浏览器会对inline元素内的文本和空格进行拉伸,注意不是inline-table和inline-block)。
  7. 如果一个行框无法容纳多个inline元素,那他们会被分布到两个或多个垂直堆叠的行框内。
  8. 如果一个inline元素的宽度超过行框能容纳的宽度,那它会被切割成若干盒子然后跨行框分布,而且被切割处margins, borders, 和padding均不生效(e.g.段落)。如果这个inline元素不能被分割(e.g.单个单词/work breaking规则被禁用/受行框内white-space为nowrap或pre的影响),那么这个inline元素会直接溢出行框。

用途

水平居中

根据IFC的布局规则: 水平方向上,通过text-align改变对齐方式。

垂直居中

根据IFC的布局规则: 垂直方向上,通过vertical-align改变对齐方式。

GFC 网格布局格式化上下文

声明display:grid/inline-grid能创建一个网格容器,网格容器会为其内容产生GFC。

网格布局引入了二维网格布局系统,通过一组相交的水平线和垂直线来定义网格的列和行,网格元素被布局到这些行和列相关的位置上。

布局规则

参考网格布局

FFC 弹性格式化上下文

声明display:flex/inline-flex能创建一个弹性容器,弹性容器会为其内容产生FFC。

布局规则

参考弹性布局

参考链接:

MDN: Block_formatting_context

W3C: block-formatting

W3C: inline-formatting