分享

CSS2 BFC模型和IFC模型 | 且码且珍惜

 jicemoon 2015-12-14

对于BFC(Block Formatting Context-块级格式化上下文)和IFC(Inline Formatting Context-行级格式化上下文)之前有一点点的了解,但是没有去深入。比如以前每次用vertical-align这个属性时,经常是无法做到垂直居中却百思不得其解,今天整理了下相关知识记录在此。

  1. CSS框模型
  2. CSS视觉格式化模型
  3. BFC是什么

1. CSS框模型

Box 是 CSS 布局的对象和基本单位, 直观点来说,就是一个页面是由很多个 Box 组成的。CSS 框模型描述了为文档树中的元素而生成的矩形框。这些框会按照视觉格式化模型来排列显示。
框模型(Box model)
每个框都有一个内容区域(例如文本、图像等)及周围可选的内边距、边框和外边距区域;每个区域的大小由以下定义的各属性指定。下图展示了这些区域之间的关系,以及用于描述外边距、边框和内边距片段的相关术语。
框模型
外边距、边框和内边距都可被打散为四个片段,分别位于上、右、下、左。(例如,图中,“LM”指左外边距、“RP”指右内边距、“TB”指上边框等)。

四个区域(内容、内边距、边框和外边距)的每一个边界被称作一个“边缘”,所以每个框都有四个边缘。
一个框之内容区域的大小,即内容宽度和内容高度,由几个因素决定:生成该框的元素是否设置了widthheight属性、框是否包含文本或其他框、框是否是一个表格等。IE的框模型有点怪异,它把内容,内边距(padding)和边框(border)全部包括在一个指定的宽度或高度之内。这导致它呈现出一个比遵从标准行为的结果更窄或者更短的框模型。

一个框的内容、内边距和边框区域的背景样式由生成它的元素的?background?属性来指定。外边框的背景总是透明的。

margin-topmargin-bottom在非替代行内元素上不起作用。margin可为负值,padding不行。

折叠外边距(Collapsing margins)
在 CSS 中,两个以上的框(可能是兄弟,也可能不是)之间的相邻外边距可以被合并成一个单独的外边距。通过此方式合并的外边距被称为折叠,且产生的已合并的外边距被称为折叠外边距。水平外边距不会合并。除了:

  1. 根元素的框的外边距不合并。
  2. 如果一个有间隙的元素的上、下外边距相邻,则其外边距将与下面的兄弟的外边距合并,但产生的边距不会与父亲区块的下外边距合并。

当且仅当下列情况发生,则称两个外边距相邻:

  1. 双方都是同一个块格式化上下文中的浮动块级框。
  2. 没有行框、没有间隙、没有内边距且没有边框隔开它们(注意,某些零高度行框会为此被忽略。)
  3. 双方的框边缘垂直相邻,例如下列一种形式:
  4. 框的上外边距和其属于正常排版(normal flow)的第一个孩子的上外边距。
  5. 框的下外边距和其属于正常排版的下一个兄弟的上外边距。
  6. 属于正常排版的最后一个孩子的下外边距和其父亲的下外边距,如果其父亲的高度计算值为?auto?。
  7. 框的上、下外边距,如果该框没有建立新的区块格式上下文,且?min-height?计算值为零、?height?计算值为零或?auto?、且没有属于正常排版的孩子。

上述规则意味着:

  1. 在浮动框和其他框之间的外边距不会折叠(甚至一个浮动框和其属于正常排版的孩子之间也不会出现外边距折叠)。
  2. 创建了新块格式化上下文的元素(例如浮动的以及overflow不是visible的元素),不会与其属于正常排版的孩子出现外边距折叠。
  3. 绝对定位框的外边距不会折叠(和其属于正常排版的孩子也不折叠)。
  4. 行内块框的外边距不会折叠(和其属于正常排版的孩子也不折叠)。
  5. 属于正常排版的一个块级元素其下外边距总是与其属于正常排版的下一个块级兄弟的上外边距折叠,除非这两兄弟之间有间隙。
  6. 如果属于正常排版的一个块元素没有上边框、上内边距,且其第一个浮动的块级孩子没有间隙,则该元素的上外边距会与其属于正常排版的第一个块级孩子的上外边距折叠。
  7. 如果一个height为auto且min-height为零的浮动的块框没有下内边距和下边框,且其属于正常排版的最后一个块级孩子没有与任何其它带间隙的上外边距出现折叠,则该框的下外边距会与该孩子的下外边距折叠。
  8. 如果一个框的min-height属性为零,且没有上或下边框以及上或下内边距,且height为 0 或者auto,且不包含行框,且其属于正常排版的所有孩子的外边距都折叠了,则折叠其外边距。

2. CSS视觉格式化模型

包含块containing block
containing block(包含块):是视觉格式化模型的一个重要概念,它与框模型类似,也可以理解为一个矩形,而这个矩形的作用是为它里面包含的元素提供一个参考,元素的尺寸和位置往往是由该元素所在的包含块决定的。也就是说一个元素盒子的位置和大小有时是通过相对于一个特定的长方形来计算的,这个长方形就被称之为元素的 containing block。“框的包含块”表示“框所处的包含块”,而不是其产生的包含块。每个框会被给予一个相对于其包含块的位置,但它不会被局限在其包含块内;它有可能会溢出。

为什么定位了的元素还总是以浏览器窗口的左上角为坐标呢? 因为并不是每个元素都能为其后辈元素生成一个包含块。

建立包含块的规则如下:

  1. 根元素”的包含块(也叫初始包含块)由user-agent生成,在HTML中,根元素是HTML元素,尽管有的浏览器会不正确地使用body元素。

  2. 如果元素的位置是’relative’ 或者 ‘static’,元素的包含块设置为最近的块级祖先元素的Content edge。

  3. 如果元素设置了’position: fixed’,包含块由viewport创建

  4. 对那些使用绝对(absolute)作为定位(postition)的非根元素,包含块设为最近的定位(postition)不是静止(static)的祖先元素(任何类型)。有以下几种情况:

      a.如果祖先元素是块级(block)元素,包含块设为祖先元素的Padding edge。

      b.如果祖先元素是内联(inline)元素,包含块设为祖先元素的Content edge。

  5. 如果没有祖先元素,包含块是根元素盒子的内容边界确定。

因此,绝对定位的元素往往以浏览器可视区域的左上为坐标原点来进行定位了。

块级元素、块容器框和块框 Block-level elements 、block container box and block boxes
块级元素是源文件中会被格式化成块状(例:段落)的元素。 ‘display’属性的以下取值会让一个元素成为块级元素: ‘block’、’list-item’、’table’。每个块级元素生成一个主要的块级框来包含其子框和生成的内容,同时任何定位方案都会与这个主要的框有关。块级框是参与块格式化上下文BFC的框。

除了 table框,和可替换元素,一个块级框同时也是一个块容器框,一个块容器框要么只包含块级框,要么创建一个行格式化上下文而只包含行级框。并非所有的块容器框都是块级框:不可替换的inline -block和不可替换的 table-cell 也是块容器但不是块级框。是块级框的块容器称作块框。
block

匿名块框
有这样一个文档:

<DIV>
Some text
<P>More text
</DIV>

(并假定 DIV 和 P 都设置了’display: block’),DIV 似乎同时包含了行内类型的内容和块类型的内容。为了使格式化简单一些,我们假定有一个匿名块框围绕在”Some text”周围。
anonymous box
换句话说:如果一个块容器框(如上例中为 DIV 生成的框)有一个块级框(如上例中的 P),那么我们强制它只包含块级框在其中。

当一个行内框(inline box)包含一个属于normal flow的块级框,这个行内框(及与其位于同一行框(line box)的行内祖先)会被从周围的块级框(及其连续的块级兄弟 )中分离出来,把行内框分离成两个框,它在块级框两边。在打断之前和打断之后的行框都附入匿名块框,并且该块级框与匿名块框成为兄弟。当这样的行内框受到相对定位影响,任何产生的移动同样影响到包含在行内框内的块级框。

该模型将应用在下面的例子中:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HEAD>
<TITLE>Anonymous text interrupted by a block</TITLE>
<STYLE>
p { display: inline }
span { display: block } 
</STYLE>
</HEAD>
<BODY>
<P>
This is anonymous text before the SPAN。
<SPAN>This is the content of SPAN.</SPAN>
This is anonymous text after the SPAN。
</P>
</BODY>
<!--p 元素包含一段匿名文本(C1),随后是一个块级元素,再随后是另一段匿名文本(C2)。对此生成了一个代表 BODY 的块
框,它包含了围绕 C1 一个匿名块框、代表 SPAN 的块框,和围绕 C2 的另一个匿名块框。-->

inline anonymous
匿名框的继承属性会从包含它的非匿名框那里继承。匿名框的非继承属性将取其初始值。例如,匿名框的字体属性继承自 DIV,但是外边距是 0。 当一个元素导致了匿名块框的生成,则该元素上设置的属性依样能应用于该元素生成的框和其内容之上。例如,在上面例子中,如果在 P 元素上设置了边框,则这个边框将画在 C1(在最后一行下方开放)和 C2(在第一行上方开放)周围。

行级元素、行内框和行级框 Inline-level elements 、 inline boxes and inline-level boxes
行级元素是在源文档中那些不为其内容不形成新的块;而让其内容分布在多行中的元素(如,段落内着重的文本,行内图形等等)。以下的’display’属性值产生一个行级元素:’inline’, ‘inline-table’, and ‘inline-block’。行级元素生成行级框,而这些框会参与某个行格式化上下文。

一个行内框是行级框,且其内容参与了包含它的行格式化上下文。一个’display’值是’inline’的非替换元素会生成一个行内框。那些不是行内框的行级框(例如可替换的行级元素、inline-block元素和 inline-table元素)被称为原子行级框,因为它们是以单一不透明框的形式来参与其行格式化上下文。
inline box

匿名行内框
任何直接被包含在一个块容器元素(而不是行内元素)中的文本必须视为匿名行内元素。

在如下的文档中:

<P>Some <EM>emphasized</em> text</P>

P 元素生成一个块框,其内还有几个行内框。”emphasized”的框是由行内元素(EM)产生的一个行内框,而其它的框(“Some”和”text”)是块类元素(P)产生的行内框。后者就称为匿名行内框,因为它们没有与之相关的行级元素。

这样的行内框从其父块框那里继承可以继承的属性。非继承属性取其初始值。例子中,匿名行内框的颜色继承自 P,而背景是透明的。空格内容,如果可被折叠(根据’white-space’属性),则其不会生成任何匿名行内框。

inline-block这个值让元素产生一个行级块容器。行内块(inline-block)的内部会被当作块容器来格式化,而此元素本身会被当作原子行级框来格式化。

定位方案 Positioning schemes

  1. 正常排版normal flow。正常排版包括对块级框的块格式化bfc,对行级框的行格式化ifc,对块级框和行级框的相对定位。

  2. 浮动。在浮动模型中,一个框先按照正常排版来摆放,再将它从排版流中取出并尽可能地向左或向右偏移。其它内容可以排在一个浮动的周围。

  3. 绝对定位。在绝对定位模型中,一个框会从排版流中完全脱离出来(它对后续的兄弟没有影响),并相对其包含块来指定其位置。

一个元素如果它是浮动、绝对定位或根元素,则被称为排版流之外out of flow的元素。

user-agent可将根元素上的position视为static正常排版normal flow。

‘display’、 ‘position’ 与 ‘float’ 的关系
影响框的生成和布局的三个属性——’display’,’position’和’float’——间的相互关系如下:

  1. 如果’display’值为’none’,那么’position’和’float’无效,元素不生成框。
  2. 否则,如果’position’值为’absolute’或者’fixed’,框绝对地定位’float’计算的值为’none’,并且 display 根据下面的表格进行设定。框的位置由’top’, ‘right’,’bottom’和’left’属性和包含块决定。
  3. 否则,如果’float’的值不是’none’,该框是浮动的,且’display’值根据下面的表格进行设定。
  4. 否则,如果元素是根元素,’display’值根据下面的表格进行设定,除了其在 CSS2.1 里面没有定义是否指定值’list-item’对应计算值’block’或者’list-item’。
  5. 否则,’display’ 的计算值为指定的值。
指定值 计算值
inline-table table
inline, table-row-group, table-column, table-column-group, table-header-group, table-footer-group, table-row, table-cell, table-caption, inline-block block
其他 与指定值相同

3. BFC是什么

框在正常排版noraml flow中必然属于一个格式化上下文,要么是块格式化上下文,要么是行格式化上下文。块级框参与块格式化上下文。行级框参与行格式化上下文。

Formatting context 是 W3C CSS2.1 规范中的一个概念。它是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用。最常见的 Formatting context 有 Block fomatting context (简称BFC)和 Inline formatting context (简称IFC)。

BFC(Block formatting context)直译为”块级格式化上下文”。它是一个独立的渲染区域,只有Block-level box参与, 它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

BFC布局规则:

  1. 内部的Box会在垂直方向,一个接一个地放置。
  2. Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  3. 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  4. BFC的区域不会与float box重叠,常用来清除浮动和布局。
  5. BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  6. 计算BFC的高度时,浮动元素也参与计算
    haslayout

哪些元素会生成BFC:

  1. 根元素
  2. float属性不为none 浮动框
  3. position为absolute或fixed
  4. display为inline-block, table-cell, table-caption, flex, inline-flex 非块框的块容器
  5. overflow不为visible的块框。这就是为什么我们经常用overflow:hidden去清除内部浮动的原因
  6. 触发IE的hasLayout特性

IFC布局规则:

  1. 框会从包含块的顶部开始,一个接一个地水平摆放。
  2. 摆放这些框的时候,它们在水平方向上的外边距、边框、内边距所占用的空间都会被考虑在内。在垂直方向上,这些框可能会以不同形式来对齐:它们可能会把底部或顶部对齐,也可能把其内部的文本基线对齐。能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框。水平的margin、padding、border有效,垂直无效。不能指定宽高。
  3. 行框的宽度是由包含块和存在的浮动来决定。行框的高度由行高计算这一章所描述的规则来决定。

行框一定会高到足以容纳它所包含的全部框。然而,它也可能比它所包含的最高的框还要高(例如:这些框是以基线对齐)。当框 B 的高度小于包含它的行框时,则 B 在行框中垂直对齐的位置由’vertical-align’ 属性来决定。当几个行级框在水平方向上无法塞得进同一个行框时,它们会被分布在两个或多个垂直堆放的行框中。行框会以既没有垂直间距 也没有重叠的方式被垂直堆放起来。

通常,行框的左边紧贴其包含块的左边,而行框的右边紧贴其包含块的右边。然而,浮动框可以插在包含块边缘与行框边缘之间。因此,尽管在同一个IFC中的行框通常有同样的宽度(也就是其包含块的宽度),但它们的宽度也可能受浮动让水平可用空间减少的影响而有所改变。在同一个IFC中,行框的高度通常是变化的(例如:某一行包含了一个比较高的图片,而其它行只包含文本)。

当一行上的行级框的总宽度小于包含它们的行框的宽度,则它们在行框内的水平分布由’text-align’属性来决定。

当一个行内框的宽度超过了行框的宽度,则它会被分割成几个框,而这些框会分布在几个行框。如果此行内框不可分割(例如:单个字符、或语言指定的文字打断规则不允许在此行内框中出现打断、或该行内框受 white-space 属性为 nowrap或 pre 的影响),那么该行内框溢出该行框。

行内框被分割的时候,外边距、边框和内边距在出现分割的地方都没有视觉效果。

以下段落(由块级元素 P 创建)包含由元素 EM 和 STRONG 间隔的匿名文本:

<P>Several <EM>emphasized words</EM> appear
<STRONG>in this</STRONG> sentence, dear.</P>

P 元素产生一个块框,它包含了五个行内框,其中的三个是匿名的:

  1. 匿名:”Several”
  2. EM: “emphasized words”
  3. 匿名:”appear”
  4. STRONG: “in this”
  5. 匿名:”sentence, dear.”

为了格式化这一段,用户代理将这五个框排入行框内。本例中,为 P 元素生成的框生成了行内框的包含块。如果该包含块足够宽,则这所有的行内框将放在一个行框内:

行高计算 ― ‘line-height’ 与 ‘vertical-align’ 属性
user-agent将行内级框流入垂直堆叠的行框内。行框的高度由下面步骤决定:

  1. 计算行框里的各行内级框的高度。对于置换元素、行内块元素、行内表格元素来说,这是边界框的高度,对于行内框来说,这是其 ‘line-height’。
  2. 行内级元素根据其 ‘vertical-align’ 属性垂直对齐。在这些框使用 ‘top’ 或 ‘bottom’ 对齐的情况下,user-agent必须以最小化行框的高为目标对齐这些框。若这些框够高,则存在多个解而 CSS 2.1 不定义行框基线的位置。
  3. 行框的高是最顶端框的顶边到最底端框的底边的距离。

在内容由行内级元素组成的块容器元素上,’line-height’ 可以用来指定元素里行框的“最小”高度。最小高度由基线之上的最小高度与基线之下的最小深度组成,就如同每一个行框由一个零宽,具有原来元素的字体与行高属性的行内框开始。

来个转载过来的应用,不定高度图片垂直居中:
vertical align

<div style="border: 1px solid #CCC; height: 200px;">
    <span style="width: 1px; display: inline-block; margin-right: -1px; height: 100%; vertical-align: middle;"></span>
    <img src="http://images.cnblogs.com/cnblogs_com/onlysea/304895/r_474.jpg" width="100" style="vertical-align: middle;" />
</div>

  一个无语义的span,用于使line box高度与div一样。计算line box的baseline,这里参与计算的只有strut box这个臆想的box,算出baseline,用span的垂直中心对齐,这时span就会像上移动,而span又是支撑这个line box高度的,等于line box往上移,用line box的中心对齐line box 的baseline,这样line box的垂直中线就是baseline。img 的middle就按这个baseline 做为基础来对齐。所以就居中了。


参考文献以及相关网址:

  1. CSS2规范
  2. 前端开发理论热点面对面:从怎么看到怎么做
  3. vertical-align的理解
  4. BFC 神奇背后的原理

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多