在解释BFC之前要先介绍Box,Formatting context的概念
Box是css布局的基本单位,直观地看来,就是一个页面都是由许多的Box组成的。也就是我们常说的盒子模型。HTML元素的类型决定了这个Box的类型。不同的Box会参与不同的Formatting Context(一个决定如何渲染文档的容器),因此Box内的元素会以不同的方式渲染。下面介绍下有哪些盒子模型:
- block-level
:当display设置为block,list-item,table的元素或者元素本身就有这种属性的元素,会生成iblock-level box 参与到Block formatting Context中
- inline-level
:当display设置为inline,inline-block,inline-table的元素会生成inline-level box参与inline Formatting Context中
Formatting Context是页面中的一块渲染区域,并且有一套渲染规则,他决定了其子元素将如何定位,以及各其他元素的关系和相互作用。
最常见的也就是上面说的BFC(Block Formatting Context)和IFC(Inline Formatting Context),这是css2.1中的规范在css2.1中也只有两个,在css3中还增加了GFC和FFC
在进一步说明BFC之前还要介绍一下css的可视化格式模型(visual Formatting Model)中非常重要地位的概念–定位方案。定位方案是指的是元素的布局,在css2.1中有三种定位方案——普通流 (Normal Flow) 、浮动 (Floats) 和绝对定位 (Absolute Positioning) ,下面分别对这三种布局简略说明一下。
在普通流中,元素按照其在 HTML 中的先后位置至上而下布局,在这个过程中,行内元素水平排列,直到当行被占满然后换行,块级元素则会被渲染为完整的一个新行, 除非另外指定,否则所有元素默认都是普通流定位,也可以说,普通流中元素的位置由该元素在 HTML 文档中的位置决定。
在浮动布局中,元素首先按照普通流的位置出现,然后根据浮动的方向尽可能的向左边或右边偏移,其效果与印刷排版中的文本环绕相似。
在绝对定位布局中,元素会整体脱离普通流,因此绝对定位元素不会对其兄弟元素造成影响(这点与浮动元素会影响兄弟元素是不同的),而元素具体的位置由绝对定位的坐标决定。
BFC 就是属于普通流的。
Block Formating Context(中文名是块级格式化上下文)是css2.1规范中的一个重要的概念,他决定了元素如何对其内容进行定位,以及与其他元素的关系的相互作用。它是一个独立的渲染区域,只有Block-level Box
参与,他规定了内部的Block-Level Box
如何布局,与这个区域外部毫无关系。
w3c规范对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.
In a block formatting contex
t, boxes are laid out one after the other, vertically, beginning at the top of a containing block. The vertical distance between two sibling boxes is determined by the ‘margin’ properties. Vertical margins between adjacent block-level boxes
in a block formatting context
collapse.
In a block formatting context
, each box’s left outer edge touches the left edge of the containing block (for right-to-left formatting, right edges touch). This is true even in the presence of floats (although a box’s line boxes may shrink due to the floats), unless the box establishes a new block formatting context
(in which case the box itself may become narrower due to the floats).
强调的内容已经做了标记,翻译为中文就是:
浮动元素和绝对定位元素,非块级盒子的块级容器(例如 inline-blocks, table-cells, 和 table-captions),以及overflow值不为“visiable”的块级盒子,都会为他们的内容创建新的块级格式化上下文。
在一个块级格式化上下文里,盒子从包含块的顶端开始垂直地一个接一个地排列,两个盒子之间的垂直的间隙是由他们的margin 值所决定的。两个相邻的块级盒子的垂直外边距会发生叠加。
在块级格式化上下文中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘),即使存在浮动也是如此,除非这个盒子创建一个新的块级格式化上下文。
说了这么到底什么是BFC呢?
千言万语汇成一句话:BFC就是一种属性(相当一个人(元素)具有一种本领(BFC属性)),这种属性会影响元素的定位和与其他元素之间的相互作用,一旦一个元素拥有了BFC属性,就代表这个元素内部的所有物质(自己定义的,元素的集合)与这个元素以外的元素就没有关系了。
在上面的官方解释中已经大致说了一下,在这里在总结一下:
- 浮动元素(除了float:none;以外)
- 绝对定位元素 (position为absolute,mixed)
- display为下面的值其一:inline-block,table-cells,table-captions
- overflow除了visible以外的值(hidden,auto,scroll)
但是,”display:table” 本身并不产生 BFC,而是由它产生匿名框,匿名框中包含 “display:table-cell” 的框会产 BFC。 总之,对于 “display:table” 的元素,产生 BFC 的是匿名框而不是 “display:table”。
一句话总结:上面说过了BFC不是元素而是某些元素带有的一种属性,因此是上面的某种元素产生
了BFC,二他们的本身并不是BFC
根据第一条中官方文档中所说
BFC的特性可以总结为一下的三点:
一句话总结:遇到css的问题多往原理上想一想
haslayout 是Windows Internet Explorer渲染引擎的一个内部组成部分。在Internet Explorer中,一个元素要么自己对自身的内容进行计算大小和组织,要么依赖于父元素来计算尺寸和组织内容。为了调节这两个不同的概念,渲染引擎采用了 hasLayout 的属性,属性值可以为true或false。当一个元素的 hasLayout 属性值为true时,我们说这个元素有一个布局(layout)
当一个元素有一个布局时,它负责对自己和可能的子孙元素进行尺寸计算和定位。简单来说,这意味着这个元素需要花更多的代价来维护自身和里面的内容,而不是依赖于祖先元素来完成这些工作。因此,一些元素默认会有一个布局。当我们说一个元素“拥有layout”或“得到layout”,或者说一个元素“has layout” 的时候,我们的意思是指它的微软专有属性 hasLayout 被设为了 true 。一个“layout元素”可以是一个默认就拥有 layout 的元素或者是一个通过设置某些 CSS 属性得到 layout 的元素。如果某个HTML元素拥有 haslayout 属性,那么这个元素的 haslayout 的值一定只有 true,haslayout 为只读属性 一旦被触发,就不可逆转。通过 IE Developer Toolbar 可以查看 IE 下 HTML 元素是否拥有haslayout,在 IE Developer Toolbar 下,拥有 haslayout 的元素,通常显示为“haslayout = -1”。
负责组织自身内容的元素将默认有一个布局,主要包括以下元素(不完全列表):
body and html
table, tr, th, td
img
hr
input, button, file, select, textarea, fieldset
marquee
frameset, frame, iframe
objects, applets, embed
对于并非所有的元素都默认有布局,微软给出的主要原因是“性能和简洁”。如果所有的元素都默认有布局,会对性能和内存使用上产生有害的影响。
大部分的 IE 显示错误,都可以通过激发元素的 haslayout 属性来修正。可以通过设置 css 尺寸属性(width/height)等来激发元素的 haslayout,使其“拥有布局”。如下所示,通过设置以下 css 属性即可。
display: inline-block
height: (任何值除了auto)
float: (left 或 right)
position: absolute
width: (任何值除了auto)
writing-mode: tb-rl
zoom: (除 normal 外任意值)
Internet Explorer 7 还有一些额外的属性(不完全列表):
min-height: (任意值)
max-height: (除 none 外任意值)
min-width: (任意值)
max-width: (除 none 外任意值)
overflow: (除 visible 外任意值)
overflow-x: (除 visible 外任意值)
overflow-y: (除 visible 外任意值)
position: fixed
其中 overflow-x 和 overflow-y 是 css3 盒模型中的属性,目前还未被浏览器广泛支持。
对于内联元素(默认即为内联的元素,如 span,或 display:inline; 的元素),
width 和 height 只在 IE5.x 下和 IE6 或更新版本的 quirks 模式下触发 hasLayout 。而对于 IE6,如果浏览器运行于标准兼容模式下,内联元素会忽略 width 或 height 属性,所以设置 width 或 height 不能在此种情况下令该元素具有 layout。
zoom 总是可以触发 hasLayout,但是在 IE5.0 中不支持。
具有“layout” 的元素如果同时 display: inline ,那么它的行为就和标准中所说的 inline-block 很类似了:在段落中和普通文字一样在水平方向和连续排列,受 vertical-align 影响,并且大小可以根据内容自适应调整。这也可以解释为什么单单在 IE/Win 中内联元素可以包含块级元素而少出问题,因为在别的浏览器中 display: inline 就是内联,不像 IE/Win 一旦内联元素拥有 layout 还会变成 inline-block。
当网页在 IE 中有异常表现时,可以尝试激发 haslayout 来看看是不是问题所在。常用的方法是给某元素 css 设定 zoom:1 。使用 zoom:1 是因为大多数情况下,它能在不影响现有环境的条件下激发元素的 haslayout。而一旦问题消失,那基本上就可以判断是 haslayout 的原因。然后就可以通过设定相应的 css 属性来对这个问题进行修正了。建议首先要考虑的是设定元素的 width/height 属性,其次再考虑其他属性。
对 IE6 及更早版本来说,常用的方法被称为霍莉破解(Holly hack),即设定这个元素的高度为 1% (height:1%;)。需要注意的是,当这个元素的 overflow 属性被设置为 visible 时,这个方法就失效了。或者使用 IE 的条件注释。
对 IE7 来说,最好的方法时设置元素的最小高度为 0 (min-height:0;)。
这时我们需要注意一个问题:既然 hasLayout 有着跟 BFC 相似的功能,那么在实际开发中,就要为需要触发 BFC 的元素同时触发 hasLayout ,这样 BFC 和 hasLayout 具有的一些特殊性质可以在现代浏览器和 IE 中同时产生,避免一个元素在不同浏览器间的表现因为 BFC 或 hasLayout 出现差异。事实上,在实际开发中很多莫名其妙的问题其实都是因此而产生的。当然同样地,如果一个元素没有触发 BFC ,也要尽量保证它没有触发 hasLayou