hasLayout与Block formatting contexts的学习(下)

BFC布局规则css

  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每一个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,不然相反)。即便存在浮动也是如此。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算。
  • 在CSS3中,对这个概念作了改动:http://www.w3.org/TR/css3-box/#block-level0
    在CSS3中,将BFC 叫作 flow root。

简单示例:
1.自适应两栏布局
代码以下:html

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            body{
                width:350px;
                position:relative;
            }
            div.sidebar{
                float:left;
                width:100px;
                height:200px;
                background-color:#9deaf1;
            }
            div.main{
                height:300px;
                background-color:#5dc2f6;
            }
        </style>
    </head>
    <body>
        <div class="sidebar"></div>
        <div class="main"></div>
    </body>
    </html>

页面效果图:css3

上述示例,正好反映了BFC布局规则:每一个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,不然相反)。即便存在浮动也是如此。
因此,sidebar虽然存在浮动,但main的左边依然与包含块的左边相接触。浏览器

2.BFC的区域不会与float box重叠。示例以下:app

代码:ide

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            body{
                width:350px;
                position:relative;
            }
            div.sidebar{
                float:left;
                width:100px;
                height:200px;
                background-color:#9deaf1;
                
            }
            div.main{
                height:300px;
                background-color:#5dc2f6;
                overflow:hidden;
            }
        </style>
    </head>
    <body>
        <div class="sidebar"></div>
        <div class="main"></div>
    </body>
    </html>

页面效果图:

经过overflow:hidden;触发main的BFC,main区域没有与float的sidebar重叠。说明了BFC的区域不会与float box重叠。布局

3.计算BFC的高度时,浮动元素也参与计算。url

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.wrapper{
                width:300px;
                border:2px solid #5dc2f6;
            }
            div.box{
                width:100px;
                height:200px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
                float:left;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
            <div class="box"></div>
            <div class="box"></div>
        </div>
    </body>
    </html>

页面效果图:spa

咱们经过设计

div.wrapper{
        width:300px;
        border:2px solid #5dc2f6;
        overflow:hidden;
}

overflow:hidden; 触发wrapper的BFC,
清除box的浮动带来的影响,获得的页面效果图以下:


所以说明:计算BFC的高度时,浮动元素也参与计算。

4.清除垂直边距重叠

代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.box{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
            }
            div.m50{
                margin-bottom:50px;
            }
            div.m100{
                margin-top:100px;
            }
        </style>
    </head>
    <body>
        <div class="box m50"></div>
        <div class="box m100"></div>
    </body>
    </html>

页面效果图以下:

如图所示,Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠。因此,两个div的垂直距离变成了100px,而不是150px了。

若是咱们给第二个div套上一层wrapper,而且触发外层的BFC,那么两个div就不是同一个BFC的两个相邻的Box了,而是变成两个独立的BFC。

代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>BFC</title>
        <style>
            div.box{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                border:2px solid #5dc2f6;
            }
            div.wrapper{
                overflow:hidden;
            }
            div.m50{
                margin-bottom:50px;
            }
            div.m100{
                margin-top:100px;
            }
        </style>
    </head>
    <body>
        <div class="box m50"></div>
        <div class="wrapper">
            <div class="box m100"></div>
        </div>
    </body>
    </html>

页面效果图以下:

垂直边距再也不重叠,不是100px,而是150px了。

  • 总结

    以上事例都证实了:BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
    
      由于BFC内部的元素和外部的元素绝对不会互相影响,所以, 当BFC外部存在浮动时,它不该该影响BFC内部Box的布局,因此BFC经过改变本身的宽度,实现不与浮动box有重叠。一样的,当BFC内部有浮动时,为了避免影响外部元素的布局,BFC计算高度时会包括浮动的高度。避免margin重叠也是这样的一个道理。

hasLayout与Block formatting contexts的实例分析

一. 在触发 hasLayout 的元素和建立了 Block Formatting Contexts 的元素中,浮动元素参与高度的计算

状况1:没有建立 Block formatting contexts 的块级非替换元素,触发了 IE 的 hasLayout。

分析如下代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div.wrapper{
                width:300px;
            }
            div#container{
                background-color:#9deaf1;
                zoom:1;
            }
            span#span1{
                background-color:#5dc2f6;
            }
            div#div1{
                width:150px;
                height:50px;
                background-color:#0576b0;
            }
            div#div2{
                float:left;
                background-color:#4dd5b3;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
                <div id="container">
                    <span id="span1">simple text</span>
                    <div id="div1">in flow</div>
                    <div id="div2">float:left</div>
            </div>
        </div>
    </body>
    </html>
  • container 没有建立 Block formatting contexts。
  • container 的 'zoom:1'设置,是为了触发 IE 中的 hasLayout;
  • container 的高度值为 auto,而且 'overflow' 的值为默认的 'visible';
  • span1是一个行内元素, div1 是一个处于普通流中的块元素;
  • div2 是一个浮动的块级元素。

根据 CSS2.1 规范第 10.6.3部分的高度计算规则,在进行普通流中的块级非替换元素的高度计算时,浮动子元素不参与计算。

因此,在进行 container 高度计算时,只受 span1 和 div1的影响,应该是它们两个的高度之和,因此最终container 的高度不包括div2的高度。

页面效果图在各浏览器的效果以下:
IE6 IE7:

IE8 Firefox Chrome Safari Opera:

当去掉container的zoom:1;各浏览器表现一致:

状况2:建立了 BFC的块级非替换元素,未触发 IE 的 hasLayout。

代码以下:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div.wrapper{
                width:300px;
            }
            div#container{
                background-color:#9deaf1;
                overflow:hidden;
            }
            span#span1{
                background-color:#5dc2f6;
            }
            div#div1{
                width:150px;
                height:50px;
                background-color:#0576b0;
            }
            div#div2{
                float:left;
                background-color:#4dd5b3;
            }
        </style>
    </head>
    <body>
        <div class="wrapper">
                <div id="container">
                        <span id="span1">simple text</span>
                <div id="div1">in flow</div>
                <div id="div2">float:left</div>
            </div>
        </div>
    </body>
    </html>
  • container 的 ‘overflow:hidden;’ 建立了BFC;
  • container 的 ‘overflow:hidden;’,在 IE6 中未触发 hasLayout,但在 IE7中触发了 hasLayout;
  • container 的高度值为 ‘auto’;
  • span1是一个行内元素,div1是一个处于普通流中的块元素;
  • div2是一个浮动的块级元素。

页面效果图以下:

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera

可见,只要 container 建立了 BFC,其浮动子元素就会参与其高度计算(IE7是因为触发了hasLayout 致使与其它浏览器的效果相同)。

二.与浮动元素相邻的、触发了 hasLayout 的元素或建立了 BFC 的元素,都不能与浮动元素相互覆盖。

与浮动元素相邻的、触发了 hasLayout 的元素或建立了 Block formatting contexts的元素,都不能与浮动元素相互覆盖。若是浮动元素的两侧有足够的空间放置该元素,则元素会紧邻浮动元素放置,必要时,该元素的宽度将会被压缩。不然它们可能会定位到浮动元素的下方。

状况1:没有建立BFC的块级非替换元素,触发了 IE 的 hasLayout。

代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div#container{
                border:2px solid #ddd;
                width:300px;
                height:150px;
                background:url("http://images0.cnblogs.com/
                blog2015/790006/201508/041827351894332.png") repeat;
            }
            div#div1{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                float:left;
                filter:alpha("opacity=50");
                opacity: 0.5;
            }
            div#div2{
                background-color:green;
                zoom:1;
            }
        </style>
    </head>
    <body>
        <div id="container">
            <div id="div1">
                Float Block
            </div>
            <div id="div2"> 
                怀才就象怀孕,时间久了会让人看出来。
            </div>
        </div>
    </body>
    </html>

IE6:

IE7/IE8

Firefox/Chrome/Safari/Opera

根据 CSS 2.1 9.5 Floats 中的描述,浮动元素会覆盖普通流中的块容器。因此,div2 应该有一部分被 div1 覆盖。

状况2:建立了 BFC的块级非替换元素,未触发 IE 的 hasLayout。
代码:

<!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>hasLayout 和 BFC</title>
        <style>
            div#container{
                border:2px solid #ddd;
                width:300px;
                height:150px;
                background:url("http://images0.cnblogs.com/
                blog2015/790006/201508/041827351894332.png") repeat;
            }
            div#div1{
                width:100px;
                height:100px;
                background-color:#9deaf1;
                float:left;
                filter:alpha("opacity=50");
                opacity: 0.5;
            }
            div#div2{
                background-color:green;
                overflow:hidden;
            }
        </style>
</head>
<body>
    <div id="container">
        <div id="div1">
            Float Block
        </div>
        <div id="div2"> 
            怀才就象怀孕,时间久了会让人看出来。
        </div>
    </div>
</body>
</html>

Firefox/Chrome/Safari/Opera:

IE6:

IE7/IE8

  • div1 是一个浮动元素,背景是50%的透明
  • div2 的 ‘overflow:hidden;’ 在 IE6 中未触发 hasLayout,但在 IE7 中触发了 hasLayout。
    根据 CSS 2.1 9.5 Floats 中的描述,建立了BFC的元素不能与浮动元素重叠, 因此,div2 应该有一部分被 div1 覆盖。

三. 触发 hasLayout 的元素和建立了 BFC的元素不会与它们的子元素发生外边距折叠

状况1:没有生成BFC的块级非替换元素,触发了 IE 的 hasLayout。

代码:

<!DOCTYPE html>
        <html lang="en">
        <head>
            <meta charset="UTF-8">
            <title>hasLayout和BFC</title>
            <style>
                div.box{
                    width:100px;
                    height:100px;
                    background-color:#9deaf1;
                    border:2px solid #5dc2f6;
                }
                div.wrapper{
                    zoom:1;
                }
                div.m50{
                    margin-bottom:50px;
                }
                div.m100{
                    margin-top:100px;
                }
            </style>
        </head>
        <body>
            <div class="box m50"></div>
            <div class="wrapper">
                <div class="box m100"></div>
            </div>
        </body>
        </html>

根据 CSS 2.1 8.3.1 Collapsing margins 第一条,两个相邻的普通流中的块框在垂直位置的空白边会发生折叠现象。
经过zoom:1;在IE中触发了hasLayout,因此,垂直边距不重叠,为150px。
而BFC未触发,因此垂直边距重叠,为100px;

IE6/IE7:

IE8/Firefox/Chrome/Safari/Opera:

状况2:生成 BFC的块级非替换元素,未触发 IE 的 hasLayout。
代码:

<!DOCTYPE html>
            <html lang="en">
            <head>
                <meta charset="UTF-8">
                <title>BFC</title>
                <style>
                    div.box{
                        width:100px;
                        height:100px;
                        background-color:#9deaf1;
                        border:2px solid #5dc2f6;
                    }
                    div.wrapper{
                        overflow:hidden;
                    }
                    div.m50{
                        margin-bottom:50px;
                    }
                    div.m100{
                        margin-top:100px;
                    }
                </style>
            </head>
            <body>
                <div class="box m50"></div>
                <div class="wrapper">
                    <div class="box m100"></div>
                </div>
            </body>
            </html>

IE6:

IE7/IE8/Firefox/Chrome/Safari/Opera:

IE7此时触发了hasLayout,但IE6没有触发hasLayout。

hasLayout 和 BFC 的异同及可能产生的问题

区别

  • 在 IE8以前的版本中,没有规范中说起的 Block formatting contexts 和 Inline formatting contexts概念,而是用 hasLayout 来达到类似的目的。
  • 在 IE 中可经过设置 ‘width’、’height’、’min-width’、’min-height’、’max-width’、’max-height’、 ‘zoom’、’writing-mode’ 来触发 hasLayout,而这些特性值的设置不可以使元素建立 BFC。
  • 在 IE 中不少元素默认就是拥有布局的,如 IPUNT, BUTTON, SELECT, TEXTAREA 等,可是这些元素在标准中会造成 Inline formatting contexts。

共同点

  • 二者都是决定了对内容如何定位及大小计算的规则。
  • 二者都决定了与其余元素的相互做用的规则。
  • ‘table-cell’ 和 ‘table-caption’ 既是 hasLayout 的元素,又是能够建立 BFC 的元素。
  • 浮动元素,绝对定位元素,inline-block 元素以及除 ‘visible’ 外任意值的 overflow(IE7) 在 IE 中能够触发 hasLayout,同时在标准中,又能够建立BFC。

可能产生的兼容性问题:

因为 hasLayout 和 BFC是对一类事物的不一样理解,而且他们的启用条件不尽相同,所以若是一个元素设计时,在 IE 早期版本中触发了 hasLayout ,但在其余浏览器中又没有建立BFC,或者相反,一个元素在 IE 早期版本中没有触发 hasLayout ,在其余浏览器中却建立了 BFC(如设置了 ‘overflow:hidden’ ),将致使页面布局的重大差别。

解决方案

仅当一个元素即在 IE 早期版本中触发了 hasLayout,又在其余浏览器中建立了BFC时,才能避免上述问题的发生。即同时启用上述二者以保证各浏览器的兼容,或者相反,二者皆不启用。
        
    使元素即生成了BFC,又触发了 hasLayout
    对于触发 hasLayout 的元素,经过 CSS 设置,使它产生BFC;
    生成 BFC可是没有触发 hasLayout 的元素,经过设置 ‘zoom:1’,使其触发       hasLayout。
    使元素即没有触发 hasLayout,又没有建立 BFC。

若有错误或者不足的地方,还望指正!----妙瞳

文章参考资料:
http://www.cnblogs.com/lhb25/p/inside-block-formatting-ontext.html
http://w3help.org/zh-cn/causes/RM8002

相关文章
相关标签/搜索