float浮动布局与清除浮动

学习CSS回顾,前面总结了 position 定位布局inline-block 布局。都是在看过很多国内外相关文章后结合自己的理解整理而成。本文整理 float 相关知识。

开始

经常在其他网站的CSS文件注释里看到/*clear shit*/

认识float

看W3C对float的定义:

A float is a box that is shifted to the left or right on the current line. The most interesting characteristic of a float (or "floated" or "floating" box) is that content may flow along its side (or be prohibited from doing so by the 'clear' property). Content flows down the right side of a left-floated box and down the left side of a right-floated box.

float 有四个属性值 left、right、inherit、none。float 没有继承性,默认值为none。回顾 HTML 文档流的知识,在常规流中块元素独占一行从上至下排列,内联元素从左至右排列满后到下行继续排列。对元素设置float:left后,元素会脱离常规流,一直向左漂浮直到接触父元素的边框。position:absolute也会使元素脱离常规流。但是 float 和 absolute 对周围元素的影响是不同的。
示例代码A和B

<style>  
  div{width: 100px; height: 100px; background: #FFC336; position: absolute;
  }
</style>

<div>  
  absolute
</div>  
<span>  
  文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖
</span>
<style>  
  div{width: 100px; height: 100px; background: #FFC336; float: left;}
</style>

<div>  
  float
</div>  
<span>  
  文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素
</span>  
示例AB效果
absolute
文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖文字被绝对定位元素覆盖
float
文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素文字围绕浮动元素文字围绕浮动



如所见,绝对定位元素是真正的完全脱离常规流,后面元素当他不存在以致被覆盖,而 float 在内联元素前依然有存在感,被围绕。看上去内联元素可以识别出浮动元素。

注意:
1.内联元素在 float 后就拥有块元素属性,可以设置宽高度,这一点和 inline-block 很像。
2.浮动元素不是任性一路飘到最左或最右,它要受到父元素边界的限制。连续设置多个浮动元素时,它们会一个挨着一个飘,一行宽度不够就会换行继续飘。连续float:right几个相邻元素时,最前面的元素飘在最右边。

float带来不可预知的问题1

我们来写四个相邻的 div 方块。让前两个 div 块浮动。

示例代码C

<style>  
.block {width:100px;height:100px;}
.float {float:left;}
.green{background:#ee3e64;}
.blue {background:#44accf;}
.red{background:#b7d84b;width:150px;height:120px;}
.gray{background:#E2A741;}
</style>  
<body>  
  <div class="block green float">  </div>
  <div class="block blue float">  </div>
  <div class="block red"> 被浮动元素覆盖 </div>
  <div class="block gray">  </div>
</body>  
示例C效果
被浮动元素覆盖

演示效果中,红色方块被蓝绿浮动块覆盖!文字被蓝绿浮动块挤出红色块边界。

float带来不可预知的问题2

我们再来用一个父 div 块包含两个兄弟 div 块,分别给他们设置浮动,观察父 div 的高度变化。

示例D代码

<style>  
#wrap{border: 1px solid red;width: 300px;padding: 10px;}
#left{height: 120px;border: 1px solid blue;}
#right{height: 150px;border: 1px solid green;}
</style>

<div id="wrap">  
  <div id="left"></div>
  <div id="right"></div>
</div>  
示例D效果
这是正常状态下,wrap 包围住两个 div 块。wrap 的高度就是连个子 div 高度之和。给两个子 div 块分别设置左右浮动呢?
<style>  
#wrap{border: 1px solid red;width: 300px;padding: 10px;}
#left{height: 120px;border: 1px solid blue;
float:left;  
}
#right{height: 150px;border: 1px solid green;
float:right;  
}
</style>

<div id="wrap">  
  <div id="left"></div>
  <div id="right"></div>
</div>  
再不看效果前,你能想象出在浏览器中它是什么样子吗?
示例D效果


这时候 wrap 的高度已经无限坍塌为0,演示中存在高度是因为设置了内边距。左右两条线代表浮动块,没设置宽度才缩成线,但高度是存在的。

再然后我们分别让两个子 div 单独浮动。点此查看演示结果

总结 float 引起的问题

前面提到 float 元素会脱离文档流,覆盖块元素,并使后面文本围绕在浮动元素周旁边,文本似乎永远不会被浮动元素覆盖。父元素未设置指定高度时其高度完全由内部元素撑起,给子元素设置浮动后因为脱离文档流,父元素会认为浮动后的元素不存在,从而导致父元素高度坍塌(Collapse)。

使用float能遇到的问题来来回回就这么多。

解决问题 clear shit

float 附近经常有 clear,clear 属性可以解决浮动元素带来的隐患。clear 有五个值 left、right、both、none、inherit。默认为 none,clear属性没有继承性。

对元素设置clear:left,直白的理解就是该元素左边不会出现浮动元素。clear:both意味着左边不会、右边也不会出现浮动元素。

浮动元素会脱离常规流,影响后面元素布局,但是对 float 后面元素设置 clear 值后,元素就有识别浮动元素的能力,避免出现环绕和覆盖问题。

示例E代码

<style>  
.block {width:100px;height:100px;}
.float {float:left;}
.green{background:#ee3e64;}
.blue {background:#44accf;}
.red{background:#b7d84b;width:150px;height:120px;
  clear:left;
}
.gray{background:#E2A741;}
</style>  

  <div class="block green float">  </div>
  <div class="block blue float">  </div>
  <div class="block red">设置clear:left  </div>
  <div class="block gray">  </div>
示例E效果
设置clear:left

设置红色块clear:left后出现在浮动元素下方。

再来说高度坍塌,父元素在子元素设置浮动后高度充满变数,归根结底还是受浮动元素脱离文档流的影响。有很多解决高度坍塌的方案,原理都只有一个,就是在浮动元素后面再来个 clear 元素。清除浮动元素能识别浮动元素,找到自己的位置。这样父元素可以通过 clear 这个子元素来确定自己高度。

在浮动元素后面加个<br sytle="clear:both">就可以解决浮动元素带来的父元素高度坍塌。

示例F代码

<style>  
#wrap{border: 1px solid red;width: 300px;padding: 10px;}
#left{height: 120px;border: 1px solid blue;
float:left;  
}
#right{height: 150px;border: 1px solid green;
float:right;  
}
</style>

<div id="wrap">  
  <div id="left"></div>
  <div id="right"></div>
  <br style="clear:both">
</div>  


示例F效果


加 br 后父元素高度是解决了,但下面又多一块背景色,使用这种方法清除浮动也不适合生产使用。

一个最常用的完美清除浮动解决方案:

.clearfix:before,
.clearfix:after {
    content: " ";
    display: table;
}
.clearfix:after {
    clear: both;
}
.clearfix {
    *zoom: 1; /*为了适配IE6、7、8*/
}

这里用到伪元素 E:before 和 E:after 。这段 CSS 代码意思是在浮动元素的父元素前面、后面通过伪元素加上空内容“”,然后设置为 table 。这相当于通过 CSS 在浮动元素的前面和后面创建了 html 内容,对后面内容设置 clear:both 可以完美解决高度坍塌问题。

最后一个示例

#wrap{border: 1px solid red;width: 300px;padding: 10px;}
#left{height: 120px;border: 1px solid blue;
float:left;  
}
#right{height: 150px;border: 1px solid green;
float:right;  
}
.clearfix:before,
.clearfix:after {
    content: " ";
    display: table;
}
.clearfix:after {
    clear: both;
}
</style>

<div id="wrap" class="clearfix">  
  <div id="left"></div>
  <div id="right"></div>
  <br style="clear:both">
</div>

看看效果

示例效果

结束

博客所有代码示例效果并非截图,都是通过 div+css 在浏览器生成的效果。越是做学习总结越是觉得所知甚少,像清除浮动完美方案中clearfix:before是什么目的,暂时还没完全理解。

参考