清除浮动还是闭合浮动(Enclosing float or Clearing float)?闭合浮动的方式有哪些?

    前言:当我们开始进行网页布局的时候,就开始接触了浮动float。使用浮动,可以轻松地帮助改变文档的普通流,让div进行左浮动和右浮动,从而快速的实现基本的布局。因为任何元素都可以浮动,浮动的使用范围较广,所以,有时也会出现滥用浮动的情况。然而,因使用浮动改变了文档的普通流,常常会影响相邻元素的排列方式,就涉及到清除浮动的方式

一、清除浮动还是闭合浮动(Enclosing float or Clearing float)?

        一般,大家都比较习惯称之为浮动,但当了解其原理以后,发现称之为闭合浮动可能更为准确。

        ①清除浮动:清除是clear,对应的CSS属性是clear:left/right/both/none;                

                          1° left:停止任何活动的左浮动;

                          2° right:停止任何活动的右浮动;

                          3° left:停止任何活动的左右浮动;

            通常只想设定一个clear:both;在你想让浮动停止的元素上。在某些情况下,你会想要只取消left或right引用。

        ②闭合浮动:使浮动元素闭合,从而减少浮动带来的影响。

            两者的区别:请查看实例demo 点击打开链接


            通过以上的实例发现,其实在实际的运用中,我们想要达到的效果更确切地说是闭合浮动,而不是单纯的清除浮动,因为在footer上设置clear:both;清除浮动并不能解决实际中wrap高度塌陷的问题。

二、为何要闭合浮动?

        CSS中的定位机制:普通流,浮动,绝对定位(其中"position:fixed"是"position:absolute"的一个子类)。

        ①普通流(normal flow):很多人称之为文档流或者普通文档流,但标准里称之为普通流(normal flow),或者称之为常规流;

        ②浮动:浮动的框可以左右移动,直至它的外边缘遇到包含框或者另一个浮动框的边缘。浮动框不属于文档中的普通流,当一个元素浮动之后,不会影响到块级框的布局而只会影响内联框(通常是文本)的排列,文档中的普通流就会表现得和浮动框不存在一样,当浮动框高度超出包含框的时候,也就会出现包含框不会自动伸高来闭合浮动元素(“高度塌陷”现象)。

        正是因为浮动的这种特性,导致本属于普通流中的元素浮动之后,包含框内部由于不存在其他普通流元素,也就表现出高度为0(高度塌陷)。在实际布局中,往往这并不是我们所希望的,所以需要闭合浮动元素,使其包含框表现出正常的高度。

三、闭合浮动的原理----了解hasLayout和Block formatting contexts

        先了解一下清除浮动的各种方法:

        ①添加额外标签

        通过在浮动元素末尾添加一个空标签<div style="clear:both;"></div>,其他标签br亦可。       

<div class="wrap" id="float1">
   <h2>添加额外标签</h2>
   <div class="main left">.main{float:left;}</div>
<div class="side left">.side{float:right;}</div>
<div style="clear:both;"></div>
</div>
<div class="footer">.footer</div>

     

      优点:通俗易懂,容易掌握;

      缺点:会添加无意义的标签,有违结构与表现的分离,在后期中不宜维护。

      ②使用br标签和其自身的html属性

        小众方法,br有clear="all/left/right/none"属性。

<div class="wrap" id="float2">
    <h2>使用br标签和其自身的html属性</h2>
    <div class="main left">.main{float:left;}</di>
   <div class="side left">.side{float:right;"}</div>
   <br clear="all"/>
</div>
<div class="footer">.footer</div>

       

        优点:比空标签方式语义稍强,代码量少;

        缺点:同样有违结构与表现的分离,不推荐使用。

        ③父元素设置overflow:hidden;

           通过设置父元素overflow值设置为hidden;在IE6中还需要触发hasLayout,例如zoom:1;

<div class="wrap" id="float3" style="overflow:hidden;*zoom:1;">
   <h2>父元素设置overflow</h2>
   <div class="main left">.main{float:left;}</div>
   <div class="side left">.side{float:right;}</div>
</div>
<div class="footer">.footer</div>

          优点:不存在结构和语义化问题,代码量极少

       缺点:内容增多时,容易造成不会自动换行导致内容被隐藏掉,无法显示需要溢出的元素;04年POPO就发现overflow:hidden会导致中键失效,作为一个多标签游览控所不能接受的。

        ④父元素设置overflow:auto属性

        同样IE6需要触发hasLayout。

        优点:不存在结构和语义化问题,代码量极少;

        缺点:多个嵌套后,firefox某些情况会造成内容全选;IE中mouseover造成宽度改变时,会出现最外层模块有滚动条等,firefox早期版本会无故产生focus等。

        ⑤父元素也设置浮动

        优点:不存在结构和语义化问题,代码量极少;

        缺点:使得与父元素相邻的元素的布局会受到影响,不可能一直浮动到body,不推荐使用。

        ⑥父元素设置display:table;


         优点:结构语义化完全正确,代码量极少;

         缺点:盒模型属性已经改变,由此造成的一系列问题,得不偿失。

        ⑦使用:after伪元素

        其中,:after是伪元素,不是伪类。由于IE6-7不支持:after,使用zoom:1触发hasLayout.

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

        优点:结构和语义化完全正确,代码量居中;

        缺点:复用方式不当会造成代码量增加。

        小结:

        通过对比,以上列举的方法,无非有两类:

        其一,通过在浮动元素末尾添加一个空元素,设置clear:both属性,after伪元素其实也是通过content在元素的后面生成了内容为一个点的块级元素;

        其二,通过设置父元素overflow或者display:table属性来闭合浮动。

        通过闭合浮动原理--来了解hasLayout和Block formatting contexts

       在CSS2.1里面有一个很重要的概念,但是国内较少提到,那就是Block formatting contexts(块级格式化上下文),以下简称为BFC

        CSS3里面对这个规范做了改动,称之为:flow root,并且对触发条件进行了进一步的说明。

        那么如何触发BFC呢?

        ①float除了none以外的值;

        ②overflow除了visible以外的值(hidden,auto,scroll);

        ③display(table-cell,table-caption,inline-block);

        ④position(absolute,fixed)

        ⑤fieldset元素。

        需要注意的是,display:table;本身并不会创建BFC,但是它会产生匿名框(anonymous boxs),而匿名框中的display:table-cell可以创建新的BFC,换句话说,触发块级格式化上下文的是匿名框,而不是display:table。所以,通过display:table和display:table-cell创建的BFC效果是不一样的。

        (fieldset元素在www.w3.org里目前没有任何有关这个触发行为的信息,直到HTML5标准里才出现。有些游览器bugs(Webkit,Mozila)提到过这个触发行为,但是没有任何官方声明。实际上,即使fieldset在大多数的游览器上都能创建新的块级格式化上下文,开发者也不应该把这当做是理所当然的。CSS2.1没有定义哪种属性适用于表单控件,也没有定义如何使用CSS来给它们添加样式。用户代理可能会给这些属性应用CSS属性,建议开发者们把这种支持当做实验性质的,更高版本的CSS可能会进一步规范这个。)

            BFC的特性:

            ①块级格式化上下文会阻止外边距叠加

            当两个相邻的块框在同一个块级格式化上下文中时,它们之间垂直方向的外边距会发生叠加。换句话说,如果这两个相邻的块框不属于同一个块级格式化上下文,那么它们的外边距就不会叠加;

            ②块级格式化上下文不会重叠浮动元素

            根据规定,一个块级格式化上下文的边框不能和它里面的外边距重叠。这就意味着游览器将会给块级格式化上下文创建隐式的外边距来阻止它和浮动元素的外边距叠加。由于这个原因,当给一个挨着浮动的块级格式化上下文添加负的外边距时将会不起作用(Webkit和IE6在这点上有一个问题)。

            ③块级格式化上下文通常可以包含浮动

            通俗地来说:创建了BFC的元素就是一个独立的盒子,里面的子元素不会在布局上影响外面的元素,反之亦然,同时BFC任然属于文档中的普通流。

            至此,或许明白了为什么overflow:hidden或者auto可以闭合浮动了,真是因为父元素创建了新的BFC。现代游览器是有BFC的,从表现上来说,hasLayout可以等同于BFC。

             IE6-7的显示引擎使用的是一个称为布局(layout)的内部概念,由于这个显示引擎自身存在很多的缺陷,直接导致了IE6-7的很多显示bug。当我们说一个元素“得到layout”,或者说一个元素“拥有layout”的时候,意思是指它的微软专有属性hasLayout为此被设为了true。IE6-7使用布局的概念来控制元素的尺寸和定位,那些拥有布局(have layout)的元素负责本身及其子元素的尺寸设置和定位。如果一个元素的hasLayout为false,那么它的尺寸和位置由最近拥有布局的祖先元素控制。

        触发hasLayout的条件:

       position:absolute;

        float:left/right;

        display:inline-block;

        width:除“auto”外的任意值;

        height:除“auto”外的任意值(例如:很多人闭合浮动会用到height:1%);

        zoom:除"normal"外的任意值;

        在IE7中,overflow也变成了一个layout触发器:

        overflow:hidden/scroll/auto(这个属性在IE之前版本中没有触发layout的功能);

        overflow-x/-y:hidden/scroll/auto(CSS3盒模型中的属性,尚未得到游览器的广泛支持,在之前的IE版本中同样没有触发layout的功能);

        综上所述:

        ①在支持BFC的游览器(IE8+,firefox,chrome,safari)通过创建新的BFC闭合浮动;

        ②在不支持BFC的游览器(IE6-7),通过触发hasLayout闭合浮动。

四、闭合浮动的方法--精益求精

        在上面列举的7种闭合浮动的方法中,通过display:table-cell;display:inline-block等只要触发了BFC的属性值都可以闭合浮动。从各个方面比较,after伪元素闭合浮动无疑是相对比较好的解决方案了,下面详细说明:

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

        ①display:block;使生成的元素以块级元素显示占满剩余空间;

        ②height:0;避免生成内容破坏原有布局的高度;

        ③visibility:hidden;使生成的内容不可见,并允许可能被生成内容盖住的内容可以进行点击和交互;

        ④通过content:"."生成内容作为最后一个元素,至于content里面是点还是其他都是可以的,(firefox直到7.0content:""仍然会产生额外的空隙);

        ⑤zoom:1;触发IE hasLayout。

        通过分析发现,除了clear:both;用来闭合浮动的,其他代码无非都是为了隐藏content生成的内容,这也就是其他版本的闭合浮动为什么会有font-size:0;line-height:0;

        精益求精方案一:

      相对于空标签闭合浮动的方法似乎还是有些冗余,通过查询发现Unicode字符里有有一个“零宽度空格”,也就是U+200B,这个字符本身是不可见的,我们完全可以省略掉visibility:hidden了。      

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

        精益求精方案二:

        由Nicolas Gallagher大师提出,该方法也不存在firefox中的空隙的问题。

.cf:before,.cf:after{
   content:"";
   display:table;
}
.cf:after{
   clear:both;
}/*For ie6/7(trigger hasLayout)*/
.cf{zoom:1;}

        需要注意的是:

        上述方法用到了:before伪元素,那什么时候需要用到before呢?其实它是用来处理margin边距重叠的,由于内部元素float创建了BFC,导致内部元素的margin-top和上一个盒子的margin-bottom发生叠加。如果这不是你所希望的,那么就可以加上before,如果只是单纯的闭合浮动,after就够了。(但只使用clearfix:after时在跨游览器兼容问题会存在一个垂直边距叠加的bug,这不是bug,是BFC应该有的特性。)

     

            补充精益求精方案二:

            查看bootstrap清除浮动的CSS如下(和方案二是一样的):

.clearfix:before,.clearfix:after{
    content:"";
    display:table;
}
.clearfix:after{
    clear:both;
}
/**For IE 6-7 only**/
.clearfix{
    *zoom:1;
}   

      ● :after伪类的设置已经达到了清除浮动的目的,但还要设置:before伪类,原因如下:

             ○ :before的设置也触发了一个BFC,由于BFC有内部布局不受外部影响的特性,因此:before的设置可以阻止

margin-top的合并。

             ○这样做,其一是为了和其他清除浮动的方式的效果保持一致;其二,是为了与IE6-7下设置zoom:1;后的效果一致(即阻止margin-top的合并的效果)。

      ●  zoom:1;用于在IE6-7下触发hasLayout和contain floats。

五、总结

        在实际的开发中,改进方案一,由于存在Unicode字符不适合内嵌CSS的GB2312编码的页面,使用方案⑦完全可以解决我们的需求了;改进方案二和bootstrap中CSS的清除浮动的方法如出一辙,鉴于bootstrap框架的普及,此类方法可以较好的使用。方案③和方案④通过overflow闭合浮动,实际上已经创建了新的块级格式化上下文,这将导致其布局和相对于浮动的行为等发生一系列的变化,闭合浮动只不过是一系列变化中的一个作用而已。所以 ,为了闭合浮动去改变全局特性,这是不明智的,带来的是一系列的bug,比如firefox早期版本产生focus,截断绝对定位的层等等。始终要明白,如果单单只是需要闭合浮动,overflow就不要使用。

        如文章哪里有问题,欢迎大家留言进行指正,谢谢!


参考博客:

        浮动--学习WEB开发 点击打开链接 (https://developer.mozilla.org/zh-CN/docs/Learn/CSS/CSS_layout/Floats)

        那些年我们一起清除过的浮动 点击打开链接  (http://www.iyunlu.com/view/css-xhtml/55.html)

       如何理解CSS中的浮动布局方式?最主要的功能是什么?如何正确地使用它? 点击打开链接  (https://www.zhihu.com/question/19915431)

       清除浮动的实例demo 点击打开链接(http://www.iyunlu.com/demo/enclosing-float-and-clearing-float/index.html)

 版权声明:本文为博主原创文章,未经博主允许不得转载。


猜你喜欢

转载自blog.csdn.net/qq_26780317/article/details/80764306
今日推荐