CSS BFC和IE Haslayout介绍

BFC(Block Formatting Context)

1. BFC的定义

是 W3C CSS 2.1 规范中的一个概念,它决定了元素如何对其内容进行定位,以及与其余元素的关系和相互做用。 html

在建立了 Block Formatting Context 的元素中,其子元素会一个接一个地放置。垂直方向上他们的起点是一个包含块的顶部,两个相邻的元素之间的垂直距离取决于 ‘margin’ 特性。在 Block Formatting Context 中相邻的块级元素的垂直边距会折叠(collapse)。 编程

在 Block Formatting Context 中,每个元素左外边与包含块的左边相接触(对于从右到左的格式化,右外边接触右边), 即便存在浮动也是如此(尽管一个元素的内容区域会因为浮动而压缩),除非这个元素也建立了一个新的 Block Formatting Context 。 浏览器

从上面的定义咱们能够看到Document显示HTML元素的方式和BFC的定义很像,其实咱们能够认为Document就是最大的一个拥有BFC的元素了。 app

2. BFC究竟是什么?

当涉及到可视化布局的时候,Block Formatting Context提供了一个环境,HTML元素在这个环境中按照必定规则进行布局。一个环境中的元素不会影响到其它环境中的布局。好比浮动元素会造成BFC,浮动元素内部子元素的主要受该浮动元素影响,两个浮动元素之间是互不影响的。这里有点相似一个BFC就是一个独立的行政单位的意思。一个大的行政单位能够包含若干个小的行政单位。 布局

3. 怎样才能造成BFC

  • float的值不为none。
  • overflow的值不为visible。
  • display的值为table-cell, table-caption, inline-block中的任何一个。
  • position的值不为relative和static。

4. BFC的做用

不和浮动元素重叠

若是一个浮动元素后面跟着一个非浮动的元素,那么就会产生一个覆盖的现象,不少自适应的两栏布局就是这么作的。好比下图的效果,参考例子 ui

<div style="float:left; border: 2px solid red"> 123</div>
               <span style="border: 2px solid blue;display:block;overflow:hidden;*zoom:1">
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
               The quick brown fox jumped over the lazy dog's back.
              </span>

清除元素内部浮动

只要把父元素设为BFC就能够清理子元素的浮动了,最多见的用法就是在父元素上设置overflow: hidden样式,对于IE6加上zoom:1就能够了(IE Haslayout)。 spa

3.嵌套元素Margin边距折叠问题的解决

按照BFC的定义,只有同属于一个BFC时,两个元素才有可能发生垂直Margin的重叠,这个包括相邻元素,嵌套元素,只要他们之间没有阻挡(例如边框,非空内容,padding等)就会发生margin重叠。 .net

所以要解决margin重叠问题,只要让它们不在同一个BFC就好了,可是对于两个相邻元素来讲,意义不大,没有必要给它们加个外壳,可是对于嵌套元素来讲就颇有必要了,只要把父元素设为BFC就能够了。这样子元素的margin就不会和父元素的margin发生重叠了。 设计

IE HasLayout

1. hasLayout概述

“Layout”是一个 Internet Explorer for Windows的私有概念,它决定了一个元素如何显示以及约束其包含的内容、如何与其余元素交互和创建联系、如何响应和传递应用程序事件、用户事件等。这种渲染特性能够经过某些 CSS 属性被不可逆转地触发。而有些 HTML 元素则默认就具备”layout”。 调试

微软的开发者们认为元素都应该能够拥有一个”属性(property)”(这是面向对象编程中的一个概念),因而他们便使用了 hasLayout,这种渲染特性生效时也就是将 hasLayout 设成了 true 之时。了解hasLayout将对IE的臭虫会有更多深刻的体会甚至解决方案。

2. HasLayout定义

一个元素”获得 layout”,或者说一个元素”拥有 layout” 的时候,是指它的微软专有属性 hasLayout 为此被设为了 true 。一个”layout元素”能够是一个默认就拥有 layout 的元素或者是一个经过设置某些 CSS 属性获得 layout 的元素。

而”无layout元素”,是指 hasLayout 未被触发的元素,好比一个未设定宽高尺寸的干净 div 元素就能够作为一个”无layout祖先”。

给一个默认没有 layout 的元素赋予 layout 的方法包括设置可触发 hasLayout = true 的 CSS 属性。参考默认 layout 元素以及这些属性列表。没有办法设置 hasLayout = false , 除非把一开始那些触发 hasLayout = true 的 CSS 属性去除或重置。

3. Layout的由来

不一样于标准属性,也不像某些浏览器的私有 CSS 属性,layout 没法经过某一个 CSS 声明直接设定 。也就是说没有”layout属性”这么一个东西,元素要么自己自动拥有 layout,要么借助一些 CSS 声明悄悄地得到 layout。

下列元素应该是默认具备 layout 的:

  • <html>, <body>
  • <table>, <tr>, <th>, <td>
  • <img>
  • <hr>
  • <input>, <button>, <select>, <textarea>, <fieldset>, <legend>
  • <iframe>, <embed>, <object>, <applet>
  • <marquee>

下列 CSS 属性和取值将会让一个元素得到 layout:

  • position: absolute
    绝对定位元素的包含区块(containing block)就会常常在这一方面出问题。
  • float: left|right
    因为 layout 元素的特性,浮动模型会有不少怪异的表现。
  • display: inline-block
    当一个内联级别的元素须要 layout 的时候每每就要用到它,这也可能也是这个 CSS 属性的惟一效果–让某个元素拥有 layout。”inline-block行为”在IE中是能够实现的,可是很是不同凡响: IE/Win: inline-block and hasLayout 。
  • width: 除 “auto” 外的任意值
    不少人遇到 layout 相关问题发生时,通常都会先尝试用这个来修复。
  • height: 除 “auto” 外的任意值
    height: 1% 就在 Holly Hack 中用到。
  • zoom: 除 “normal” 外的任意值
    IE专有属性。不过 zoom: 1 能够临时用作调试。
  • writing-mode: tb-rl
    MS专有属性。

IE7中引入的hasLayout成员

  • overflow: hidden|scroll|auto
    在 IE7 中,overflow 也变成了一个 layout 触发器,这个属性在以前版本 IE 中没有触发 layout 的功能。
  • position: fixed
  • min-width: 任意值
    就算设为0也可让该元素得到 layout。
  • max-width: 除 “none” 以外的任意值
  • min-height: 任意值
    即便设为0也可让该元素的 haslayout=true
  • max-height: 除 “none” 以外的任意值

4. 有关内联级别元素

对于内联元素(能够是默认即为内联的好比 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。

5. 重置 hasLayout

没有办法设置 hasLayout = false, 除非把一开始那些触发hasLayout = true的CSS属性去除。

display 属性的不一样:当用”inline-block”设置了 haslayout = true 时,就算在一条独立的规则中覆盖这个属性为”block”或”inline”,haslayout 这个标志位也不会被重置为 false。

6. CSS hacks,如何触发hasLayout

比较经常使用的是zoom: 1,这是微软的专有属性,能够在IE6,IE7上工做,无附做用,惟一的缺点是没法经过W3C的语法验证。因此调试的时候能够先加zoom:1试试看问题是不是hasLayout的问题,若是是换成其它对应的属性。

最经常使用的就是Holly Hack,简单点讲就是添加height: 1%。若是它的父元素不能定高,这种方法就会自动转换为height: auto,可是hasLayout被触发了。优势就是这是标准的属性,能够经过W3C验证。

还有一种也常常用到的就是height: 0或者height: 1px,可是这种方法只能用在IE6上面,由于IE6以及更低的版本会把height做为min-heigth那样对待,因此把height设得很小对于显示没有任何影响。这种方法不能和overflow:hidden同时使用。

7. HasLayout的影响及做用

清除浮动

效果同BFC,就是自动清除它的浮动的直接子元素。

对于IE6和IE7,我发现即便浮动元素的父元素没有hasLayout,父元素的高度也是有的,能够经过js输出或者IEDeveloper查看,可是在IE8和其它浏览器里是没有高度的(值为0)。可是实际效果倒是没有清除浮动的效果,即该父元素的实际高度为0,只要在后面跟个元素就能够看出来了,后面的元素会和前面的元素重叠。这点让我迷惑好大一会。

不和浮动元素重叠

效果同BFC。

列表

不管是列表自己(ol, ul) 仍是单个的列表元素(li),拥有 layout 后都会影响列表的表现。不一样版本 IE 的表现又有不一样。最明显的效果就体如今列表符号上(若是你的列表自定义了列表符号则不会受这个问题影响)。这些符号极可能是经过某种内部机制附到列表元素 上的(一般是附着在它们外面)。不幸的是,因为是经过“内部机制”添加的,咱们没法访问它们也没法修正它们的错误表现。

相对定位元素(r.p.)

注意,因为 position: relative 并不触发 hasLayout,因此不少诸如内容消失或错位的渲染错误就会所以而起。这些现象可能会在刷新页面、调整窗口大小、滚动页面、选中内容等状况下出现。原 因是 IE 在据这个属性对元素作偏移处理时,却彷佛忘了发出信号让其 layout 孩子元素进行“重绘”(而若是是一个layout元素,那么在其重绘事件的信号链中,这个传给其孩子的信号是会正常发出的)。因此调试的时候能够尝试给相对定位元素触发它的hasLayout。

滤镜

MS专有的滤镜属性 filter 是只适用于 layout 元素的。好比透明效果。

背景原点

MS专有的这个 hasLayout 还会影响背景的定位和扩展。好比,根据 CSS 规范,background-position : 0 0 应该指元素的“补白边缘(padding edge)”。而在 IE/Win 下,若是 hasLayout = false 则指的是“边框边缘(border edge)”,当 hasLayout=true 时指的才是补白边缘:

嵌套元素边距折叠问题的解决

同BFC

相对容器中的绝对定位(主要是IE6)

对于绝对定位元素,包含区块是由其最近的定位祖先决定的。若是其祖先都没有被定位,那么就使用初始包含区块 html。
一般状况下咱们会用 position: relative 来设定任意包含区块。这就是说,咱们可让一个绝对定位元素所参考的原点和长度等不依赖于元素的排列顺序,这能够知足诸如“内容优先”这种可访问性概念的须要,也能够给复杂的浮动布局带来方便。
可是因为 layout 概念的存在,这种设计理念的效果在IE中就要打个问号了:由于在IE中绝对定位只有当其包含元素拥有 layout 时才会计算正确,并且绝对定位元素的百分比宽度参考也搞错了对象。这里 IE5 和 IE6 的行为不一样但都有问题。IE7b2 的行为就要好不少,虽然有些小地方仍是有错误。总之尽量的让绝对元素的包含区块拥有 layout,并且尽可能让其就是绝对定位元素的父级元素(也就是说这个包换元素和绝对定位元素之间没有绝对定位元素的别的祖先了)。

块级别的连接

hasLayout 会影响一个块级别连接的鼠标响应区域(可点击区域)。一般 hasLayout = false 时只有文字覆盖区域才能响应。而 hasLayout = true 则整个块状区域均可响应。添加了 onclick/onmouseover 等事件的任意块级元素也有一样的现象。我没能重现这个问题。

边缘裁切

一般而言,当一个盒子包含了诸如伸出其边缘的内容这种更复杂的结构时,这个容器就常常须要“hasLayout”来避免一些渲染错误。但使用这种经常使用方法又会在边界处理时左右为难,由于一个得到“layout”的元素会变成某种自封闭的盒子。内部的内容盒子会被裁切,好比使用负边距向外移动时。

被裁掉的部分当内容盒子触发了“layout”时能够再次出现,但在 IE6 中须要同时拥有 position: relative 才行。IE7 在这方面要略有改观,它再也不须要额外的 position: relative 了。

案例分析

1. 清除浮动

最原始的用法<div style="clear: both"></div>,这种用法的缺点是添加了无心义的空白标签。

overflow: hidden, 这也是常用的一种方式,但事实它的原理就是对于非IE6和IE7浏览器来讲产生了BFC,对于IE7浏览器来讲是产生了hasLayout。可是这种方式的缺点就是若是子元素超出父元素的范围会被截取。对于IE6无效,能够用zoom:1。我刚学CSS的时候一直很好奇为何overflow:hidden能够清理浮动。

如今最流行也最无害的一种方式就是:

.clearfix:after {
              content: " ";
              display: block;
              clear: both;
              height: 0;
            }
            .clearfix {
              *height: 1%;
            }

代码分析:对于非IE6和IE7等支持:after的浏览器来讲,在内容的最后面添加了一个空白元素,而后把它隐藏掉,同时添加clear: both属性,达到清理浮动的目的,对于不支持:after的浏览器来讲(主要就是IE6和IE7),设置height: 1%能够触发hasLayout从而达到清理浮动的目的。

2. 水平两栏自适应排版

见BFC不和浮动元素重叠那一节。就是第一个元素是浮动,第二个元素要触发BFC或者hasLayout来避免被浮动元素覆盖

.second-item {
               overflow: hidden;
               *zoom: 1;//IE6
             }

跨浏览器的inline-block

对于支持inline-block的浏览器来讲,display: inline-block就能够了,对于不支持的浏览器(IE6和IE7)来讲,实现方法是将元素设置成display: inline,同时触发它的hasLayout就能够了。

#item {
               display: inline-block;
             }
             #item {
               *display: inline;
             }

这个地方须要注意的是这两条必定要分开写,不能放在同一个选择器中,不然hasLayout就会被取消,那样的话就须要zoom:1,因此若是非要写在一块儿的话,代码以下:

#item {
               display: inline-block;
               *display: inline;
               *zoom: 1;
             }

事实上,在IE中,只要是触发了BFC的均可以设置宽高,若是是内联元素则就是inline-block的效果了,而拥有了BFC的元素则均可以设置宽高,除了overflow:hidden;



相关文章
相关标签/搜索