深入解析float

随笔 2016-07-22

0.前言

float属性在css2中是一个热门的属性,被广泛应用于布局之中,同时由于不当使用float带来的问题也非常多,本文结合自己对float的理解以及实际项目中碰到float的相关问题,做一个详细总结,欢迎一起探讨,但未经同意禁止转载。以下是文章的目录

  1. float的特性
  2. float与absolute的区别
  3. float与inline-block
  4. 清除浮动的方法及优缺点

1.float的特性

文字环绕

float 最早的设计目的是用于图片,使文字能够环绕在图片周围,像下面这样:

1.png

2.png

文字环绕效果是很明显的,这里要注意一个地方:浮动的块虽然脱离的正常的文档流,但是还会占有正常文档流的文本空间,可以看到上面第二种图,p的区域其实是顶到了img的底下的,因为float让img脱离文档流,但是p上的文字却没有顶过去,也就是说p上的一部分文字空间仍然被img占据着,所以从这里也可以看出float的脱离文档流不是完全脱离。

包裹性

所谓的包裹性是指,使用float的元素会自动加上一个块级框,也就是可以像块级元素那样设置宽高 ,例子如下:

3.png

4.png

破坏性


float的破坏性主要是指它会使父容器的高度塌陷,也就是父元素在高度计算的时候会忽略浮动的元素,

5.png

可以看到图中名为taxian的元素高度为0. 这个特性也正是它能够实现文字环绕的原因,但是由于后来float被大量应用到页面布局之中,所以这个我们不得不想办法清除浮动,这个在下文会有提到。

2.float和position:absolute

脱离文档流

虽然在我们常常看到描述float和absolute的时候,都陈伟脱离文档流,但是实际上并不完全相同: 在脱离文档流方面,absolut正如它的名字一般,是绝对脱离,设置了该属性的元素,将完全独立在文档流之外,不会对其他的元素产生任何影响,就举上面文字环绕的例子来说,如果把img属性的float换成position:absolue属性的话,那么p元素以及上面的文字都会顶到图片的位置上,就像这样:

absolute的完全脱离

而对于float我们之前已经提出,float只是脱离了文档流的dom空间但是还占据着文字空间(这两个名词不知道是否已经有更标准的词语出现,在这里只是个人用法,见谅)

高度塌陷

float和absolute都能引起父元素的高度塌陷,同样地,由于absolute是完全脱离文档流,所以这种情况的高度塌陷是没办法清除的;float引起的高度塌陷则是可清除的,我们常说的清除浮动就是指清除float带来的高度塌陷问题,在下文会有提到。

在两列布局中的使用

float和absolute都被广泛用于两列布局之中,absolute由于完全脱离,可以做到精准的定位,但是不利于设计两列之间的联动变化;float属性可以保留一些相互影响,但是要非常小心传递来的问题,比如clear的不当使用会导致左右布局异常联动,在后面讲清除浮动时会专门讲解。而且在使用浮动布局的时候,要注意某些情况下要交换浮动左右浮动元素的声明次序

3.float和display:inline-block

横向排列

首先,使用floatinline-block都能使li横向排列。但是,使用float可以选择排列的方向,而inline只有一种方向; 第二是在单纯排列图片的时候,如果图片大小不是完全一致的,那么使用这两个属性都能完成比较合适的排列:

7图片排列.png

但是如果图片大小不等高,float的脱离文档流特性导致排列的某些图片会被挤到下一行,导致垂直方向无法对齐,如下:

float排列的图片

而如果使用display:inline-block则可以保证垂直方向的对齐:

inlne排列的图片

所以如果是要保证垂直对齐的情况下,使用display:inline-block会比较合适

float和displayinline-block这两个属性有一个很经常用到的地方就是横向导航。导航中一般是单行对齐,而且除了图片之外还有文字,这时候如果采用display:inline-block, 必须要考虑display:inline-block属性带来的空白间隙问题(这个问题可以自行查找,本文中不赘述),此时使用float:left更为合适一些。

4.关于清除浮动

清除浮动的方式

前文中提到float属性会引起父容器高度塌陷的问题,因此我们需要清除浮动。 在阅读这块内容之前,请先了解css中的BFC(这个问题可以自行查找,本文中不赘述),在此基础上,我认为清除浮动,根据原理来划分,分为两类:

1. 利用clear属性清除浮动 2. 利用bfc原理包容浮动

首先介绍第一类,利用clear原理清除浮动,如果大家有过经验都知道,通常利用clear属性清除浮动的方式有两种:

  • 利用添加空标签清除浮动
  • 通过after伪类清除元素

这两种方式只是写法上有所不同,通过伪类清除可以让代码比较简洁,并且符合语义化的原则(其实就是可以少写无意义的空标签) 现在比较流行的bootstrap框架或者其他各大框架中,通常使用一下代码来清除:

.clearfix:before,
.clearfix:after
{
  display: table;
  content: " ";
}
.clearfix:after
{
  clear: both;
}
.clearfix{zoom:1;} //ie 6 7

其实这里起清除浮动的作用的是只是

    .clearfix:after
    {
      content: " ";
      clear: both;
    }

至于before和after中的display:table;是为了防止子元素垂直方向上的边距折叠,也就是通常说的子元素margin-top会被转移到父元素的问题(为防止篇幅过长这个问题也不在此解释,如果有需要可以私信回答) 所以以上的效果就相当于在父元素最后插入一个子元素,并且设置clear:both属性,这是现在最通用的办法,但是其实并无是完美无缺的

clear使用不当的例子

(这里为什么用了大号呢,因为这个问题很重要!很重要!很重要!)

举一个之前项目中碰到的一种情况,为了方便大家理解,在这里把模型简化,代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>float</title>
    <style>
        *{
            padding: 0;
            margin:0;
        }
        .div1{
            float: left;
            width: 100px;
            height: 100px;
            background-color: lightpink;
        }
        .div2{
            margin-left:100px;
            background-color: lightgreen;
        }
    </style>
</head>
<body>
        <div class="div1">
        这是div1
        </div>
        <div class="div2">
            <div style="float:left">这是一个浮动的标题</div>
            <div style="clear:both"></div>
        </div>
</body>
</html>

这段代码是一个非常简单的左右两列布局,在右边内部有个浮动的标题,于是在后面跟上一个清除浮动的子元素(这里采用空标签只是为了在研究问题的时候排除伪类元素的干扰),但是存在一个问题:右边的div2会自动适应div1的高度,或者说清除浮动的容器会有高度, 我们可以在f12中直接改变左边div1的高度,可以看到右边的高度也随之改变。

10clear.png

这种情况有很多方法可以处理,比如让div2形成一个bfc容器,但是很少看到有文章讲到问题的根源,我查了 很久,最后发现问题是源于clear这个属性上设计:

clear:

This property indicates which sides of an element's box(es) may not be adjacent to an earlier floating box. The 'clear' property does not consider floats inside the element itself or in other block formatting contexts.


clear:both

Requires that the top border edge of the box be below the bottom outer edge of any right-floating and left-floating boxes that resulted from elements earlier in the source document


以上是w3c文档上关于clear和clear:both的描述,大概有以下两个重点:

  • clear清除浮动对于其他形成bfc的块内部的浮动元素是无效的
  • clear清除浮动的原理是:让添加了clear属性的那个元素的top边缘在某侧或者两侧(看设置的值是left right还是both)浮动元素的底边距之下

其实这个很好理解,我们之所以能够使用clear解决float引起的父元素塌陷问题,其实就是因为加了clear的空标签或者是那么伪类元素,把top值设置在了浮动元素的bottom边缘下方,从而能够撑起父元素

所以最后我们就知道上面的问题出在哪里了:clear是清除某侧或者两侧的所有浮动,结合上面那个例子来看,其实是有两处浮动的,第一是左侧的div1,第二是在div2内部有个浮动的标题,我们的目的是要清除内部的浮动,但是因为clear本身的定义,就把两个浮动都清除了,也就是把加了clear属性的标签top值设置了浮动元素的bottom边缘下方,所以,那个块将会和左侧等高(实质应是设置了clear空标签的高度为0并且top刚好在div的下方)

总结

上面的一段说的有点拗口,不知道大家有没有理解,不过可以拿例子去跑一下,应该就很容易理解了。 既然问题找到了,那相应的解决方案也就出来了:

  1. 左侧使用absolute布局避开这个问题
  2. 给右侧div2添加overflow:auito形成bfc,从而隔离clear的作用范围

现在回到清除浮动的问题主线,关于使用bfc包含浮动的情况,了解了bfc特点后我们就知道bfc的内部是会计算浮动元素的高度的,所以直接给浮动元素父元素加上overflow:auto或者其他可以构成bfc的属性即可。

以上内容为查阅相关资料以后,结合经验的个人总结,可能有理解不到位之处,欢迎指出和讨论,同时再次声明未经允许不得转载!!

如果对您有用,您的支持将鼓励我继续创作!