iCSS icon indicating copy to clipboard operation
iCSS copied to clipboard

谈谈一些有趣的CSS题目(11)-- IFC、BFC、GFC 与 FFC 知多少

Open chokcoco opened this issue 5 years ago • 6 comments

11、IFC、BFC、GFC 与 FFC 知多少

这么多 *FC 都是些啥?

FC 即是 Formatting Contexts ,译作格式化上下文。 *FC 可以称作视觉格式化模型。CSS 视觉格式化模型(visual formatting model)是用来处理文档并将它显示在视觉媒体上的机制。这是 CSS 的一个基础概念。

比较常见的是 CSS2.1 规范中的 IFC(Inline Formatting Contexts)与 BFC(Block Formatting Contexts),至于后面两个,则是 CSS3 新增规范,GFC(GridLayout Formatting Contexts)以及 FFC(Flex Formatting Context)。

FC 是网页CSS视觉渲染的一部分,用于决定盒子模型的布局、其子元素将如何定位以及和其他元素的关系和相互作用。

理解各种 FC 背后的原理是掌握各类 CSS 布局的关键。

先了解几个概念,

Box

Box 是 CSS 布局的对象和基本单位,直观点说就是一个页面是由很多个 Box (即boxes)组成的,元素的类型和 display 属性决定了 Box 的类型。

  1. block-level Box:当元素的 CSS 属性 display 为 block, list-item 或 table 时,它是块级元素 block-level 。块级元素(比如<p>)视觉上呈现为块,竖直排列。 每个块级元素至少生成一个块级盒(block-level Box)参与 BFC ,称为主要块级盒(principal block-level box)。一些元素,比如<li>,生成额外的盒来放置项目符号,不过多数元素只生成一个主要块级盒。

  2. Inline-level Box:当元素的 CSS 属性 display 的计算值为 inline, inline-block 或 inline-table 时,称它为行内级元素。视觉上它将内容与其它行内级元素排列为多行。典型的如段落内容,有文本或图片,都是行内级元素。 行内级元素生成行内级盒(inline-level boxes),参与行内格式化上下文 IFC 。

  3. flex container:当元素的 CSS 属性 display 的计算值为 flex 或 inline-flex ,称它为弹性容器。 display:flex这个值会导致一个元素生成一个块级(block-level)弹性容器框。 display:inline-flex这个值会导致一个元素生成一个行内级(inline-level)弹性容器框。

  4. grid container:当元素的 CSS 属性 display 的计算值为 grid 或 inline-grid,称它为栅格容器。

栅格盒模型值,是一个仍处于实验中的属性。

块容器盒(block container box)

只包含其它块级盒,或生成一个行内格式化上下文(inline formatting context),只包含行内盒的叫做块容器盒子

也就是说,块容器盒要么只包含行内级盒,要么只包含块级盒。

块级盒(block-level Box)是描述元素跟它的父元素与兄弟元素之间的表现。

块容器盒(block container box)描述元素跟它的后代之间的影响。

块盒(BLock Boxes)

同时是块容器盒的块级盒称为块盒(block boxes)

顶住,概念真的很多。。。

行盒(Line boxes)

行盒由行内格式化上下文(inline formatting context)产生的盒,用于表示一行。在块盒里面,行盒从块盒一边排版到另一边。 当有浮动时, 行盒从左浮动的最右边排版到右浮动的最左边。

IFC(Inline Formatting Contexts)行内级格式化上下文

行内级格式化上下文用来规定行内级盒子的格式化规则。

先来看看如何生成一个 IFC :

IFC 只有在一个块级元素中仅包含内联级别元素时才会生成。

布局规则

  1. 内部的盒子会在水平方向,一个接一个地放置。

  2. 这些盒子垂直方向的起点从包含块盒子的顶部开始。

  3. 摆放这些盒子的时候,它们在水平方向上的 padding、border、margin 所占用的空间都会被考虑在内。

  4. 在垂直方向上,这些框可能会以不同形式来对齐(vertical-align):它们可能会使用底部或顶部对齐,也可能通过其内部的文本基线(baseline)对齐。

  5. 能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框(line box)。行框的宽度是由包含块(containing box)和存在的浮动来决定。

  6. IFC中的 line box 一般左右边都贴紧其包含块,但是会因为float元素的存在发生变化。float 元素会位于IFC与与 line box 之间,使得 line box 宽度缩短。

  7. IFC 中的 line box 高度由 CSS 行高计算规则来确定,同个 IFC 下的多个 line box 高度可能会不同(比如一行包含了较高的图片,而另一行只有文本)

  8. 当 inline-level boxes 的总宽度少于包含它们的 line box 时,其水平渲染规则由 text-align 属性来确定,如果取值为 justify,那么浏览器会对 inline-boxes(注意不是inline-table 和 inline-block boxes)中的文字和空格做出拉伸。

  9. 当一个 inline box 超过 line box 的宽度时,它会被分割成多个boxes,这些 boxes 被分布在多个 line box 里。如果一个 inline box 不能被分割(比如只包含单个字符,或 word-breaking 机制被禁用,或该行内框受 white-space 属性值为 nowrap 或 pre 的影响),那么这个 inline box 将溢出这个 line box。

那么,IFC 的具体实用在何处呢?

  • 水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过设置父容器 text-align:center 则可以使其水平居中。

值得注意的是,设置一个块为 inline-block ,以单个封闭块来参与外部的 IFC,而内部则生成了一个 BFC。

  • 垂直居中:创建一个IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。

使用 IFC 可以实现多行文本的水平垂直居中,可以看看下面这个例子:

Demo戳我:使用 IFC 可以实现多行文本的水平垂直居中

BFC(Block Formatting Contexts)块级格式化上下文

块格式化上下文(block formatting context) 是页面上的一个独立的渲染区域,容器里面的子元素不会在布局上影响到外面的元素。它是决定块盒子的布局及浮动元素相互影响的一个因素。

下列情况将创建一个块格式化上下文:

  1. 根元素或其它包含它的元素
  2. 浮动 (元素的 float 不为 none)
  3. 绝对定位元素 (元素的 position 为 absolute 或 fixed)
  4. 行内块 inline-blocks (元素的 display: inline-block)
  5. 表格单元格 (元素的 display: table-cell,HTML表格单元格默认属性)
  6. 表格标题 (元素的 display: table-caption, HTML表格标题默认属性)
  7. overflow 的值不为 visible的元素
  8. 弹性盒子 flex boxes (元素的 display: flex 或 inline-flex)

块格式化上下文包括了创建该上下文的元素的所有子元素,但不包括创建了新的块格式化上下文的子元素。

包含浮动元素的块塌缩,清除浮动等都是 BFC 的应用场景。

GFC(Grid Formatting Contexts)栅格格式化上下文

display:grid 篇幅巨大,建议看完大漠老师的教程:

CSS Grid布局

FFC(Flex Formatting Contexts)Flex格式化上下文

如上所述,当 display 的值为 flex 或 inline-flex 时,将生成弹性容器(Flex Containers)。

一个弹性容器为其内容建立了一个新的弹性格式化上下文环境(FFC)。

值得注意的是,弹性容器不是块容器,下列适用于块布局的属性不适用于弹性布局:

  1. 在CSS3多列布局模块中定义的 column-* 属性不适用于弹性容器。
  2. float 和 clear 属性对于弹性项没有作用,并不会把它带离文档流(或相反)。然而,浮动属性仍然会通过影响display属性的计算值而影响box的生成。
  3. vertical-align 属性对于弹性项没有作用
  4. ::first-line 和 ::first-letter 伪元素不适用于弹性容器,而且弹性容器不为他们的祖先提供第一个格式化的行或第一个字母。

看看下面的结构,

<div class="box">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
.box{
  display: flex;
}

如上所示,采用 Flex 布局的元素,称为 Flex 容器(flex container),简称"容器"。弹性容器中的弹性项(flex item)表示其文档流(in-flow)内容中的框。

display:flex 篇幅巨大,建议看完下面两篇:

借用一句话:“’在工作过程中遇到某个属性的使用,浏览器渲染效果与预期效果不符,只能通过死记硬背能避免或应用这种效果,不知晓背后的原理,用就是这样的的借口来搪塞自己。”,所以对于布局问题,不要死记硬背,要去理解背后的各种原理。


最后,新开通的公众号求关注,形式希望是更短的篇幅,质量更高一些的技巧类文章,包括但不局限于 CSS:

image

chokcoco avatar Mar 18 '19 11:03 chokcoco

您好,我有一个问题关于BFC的想请教您一下。查了很多资料没找到解答。

有关BFC的文章中经常可见这样一个案例:

<div class="box">
    <div class="img">image</div>
    <p class="info">信息信息信息信息信信息信息信息信息信息信息信息信息信息信息信息信信息信息信息信息信息信息信息信息信息信息信息信息信息信息信息信息信息信息信</p>
</div>
.box {width:210px;border: 1px solid #000;float: left;}
.img {width: 100px;height: 100px;background: #696;float: left;}
.info {background: #ccc;color: #fff;}

image

如果希望文字不受浮动元素影响,可以为其创建一个BFC:

.box {width:210px;border: 1px solid #000;float: left;}
.img {width: 100px;height: 100px;background: #696;float: left;}
.info {background: #ccc;color: #fff; overflow: hidden}

使用了overflow: hiddenimage

我的问题是: 这里使用了overflow: hidden创建了BFC,p元素与float在同一行排列。那么我使用display: inline-block也能创建一个BFC,为什么p元素会到新一行排列呢?

.box {width:210px;border: 1px solid #000;float: left;}
.img {width: 100px;height: 100px;background: #696;float: left;}
.info {background: #ccc;color: #fff; display: inline-block;}

image

imageslr avatar May 06 '19 13:05 imageslr

@chokcoco

imageslr avatar May 06 '19 13:05 imageslr

@imageslr 我觉得和 inline-block 外部参与 IFC 而非 BFC 有关

ItsRyanWu avatar May 21 '19 11:05 ItsRyanWu

@imageslr 如果你的 inline-block 里的文字少一些,少到单行且宽度小于 110px,那我估计 inline-block 会和绿色盒子处在同一行,因为 inline-block 的宽度由内部内容所决定,而 inline-block 参与 IFC 排版,绿色盒子处于 IFC 上,他把 inline-block 的行盒挤的更窄了,那 inline-block 排不下了他也不会向 inline 那样 wrap,所以只好将自己放在绿色盒子下方进行排列,此时 IFC 的面积被扩充的更大了。

ItsRyanWu avatar May 23 '19 10:05 ItsRyanWu

@ItsRyanwu 是的,我测试了一下确实是这样。我的理解是inline-block默认宽度是父元素的100%,所以以上的例子就换行然后宽度为100%。而块级元素的宽度默认是以格式化上下文BFC的内容区的边缘排列,所以一开始不会换行。非常感谢您的解答!

imageslr avatar May 23 '19 11:05 imageslr

以前总是小看 css 但现在细细开始品味的时候开始受益匪浅。

xiaochengzi6 avatar Jan 27 '22 10:01 xiaochengzi6