CSS浮动float详解

CSS里浮动float是个概念比较暧昧的属性,撸主最早对浮动float的认识是基于布局的,认为float元素就是用于:“让block元素无视float元素,让inline元素让流水一样围绕着float元素”来实现浮动布局。现在想想,当初真是图样图森破。

其实这个属性撸主一直是比较模糊的,感觉似懂非懂。本着和自己死磕的精神,在参考了许多大神的博文后,将我的理解整理归纳在本文中,希望能可以帮助到你。当然撸主水平有限,如有错误敬请指出。

以下是网上大神关于float的优秀文章:

CSS浮动(float,clear)通俗讲解

CSS float浮动的深入研究、详解及拓展(一)

CSS float浮动的深入研究、详解及拓展(二)

那些年我们一起清除过的浮动

浮动float的本意:

传统如C++,Java等编程语言一个API可能只能对应做一件事,即使有了模板和泛型编程,通常也只能做某一类事。但CSS是门相当灵活的语言。某个CSS属性被用于的场景,可能会完全违背当初创造该CSS属性的本意。在CSS的世界里,想实现某个效果,会有很多方法。那究竟选择哪种方法呢?有很多判断标准,如重绘,如回流,如极简主义。撸主也有一个不成熟的判断标准就是:根据该CSS属性被创造时的本意,该用哪个属性就用哪个属性。
那浮动float的本意是什么呢?是:让文字像流水一样环绕浮动元素。

怎样才能实现该效果呢?用 包裹性高度欺骗

特性一:包裹性

例1:首先来看浮动float的包裹性,所谓一图胜千言:

相关代码非常简单:

<div style="border:4px solid blue;">
    <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red;float:left;">
    <img src="img/25/2.jpg" />
</div>

所谓包裹性一目了然。block元素不指定width的话,默认是100%,一旦让该div浮动起来,立刻会像inline元素一样产生包裹性,宽度会跟随内容自适应。(这也是通常float元素需要手动指定width的原因)

再加上一个div的话,效果如下:

<div style="border:4px solid blue;">
    <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red;float:left;">
    <img src="img/25/2.jpg" />
</div>
<div style="border:4px solid green;">
    <img src="img/25/3.jpg" /> 
</div>

效果非常近似于display:inline-block。但相比之下,浮动能设定为左浮和右浮,但display:inline-block都是从左到右排列的。(还有些细微差别,两个display:inline-block间会有空隙,但两个float间没有。这不是本篇的主题,暂时略过)

特性二:高度欺骗

(首先声明:其实是CSS层级在起作用,但CSS层级适合单独写一篇,内容实在太多,不适合在这里展开,就理解为高度欺骗吧)

例1中浮动float被设在了外围div上,因此高度欺骗性没体现出来。现在给内层img元素设定float。所谓一图胜千言:


<div style="border:4px solid blue;">
    <img src="img/25/1.jpg" />
</div>
<div style="border:4px solid red;">
    <img style="border:4px solid yellow;float:left;" src="img/25/2.jpg" />
</div>

和例子1唯一的区别就是:将外层div的float移到内层img中。这下高度欺骗性体现出来了。例1中给外层div加上浮动,因此外层div会有包裹性,其内容是img图片,所以可以看到红色边框包裹着img。

例2中外层div没有了浮动,因此红色边框宽度默认是100%全屏。其内容img由于加上了float,使得该img具有了欺骗性。float给img施了个障眼法,让该img的inline-height高度塌陷为0了。这样外层div计算高度时,认为img的高度为0,相当于div的content的高度为0,因此红色边框看起来是一条直线。

但请注意障眼法毕竟是障眼法,并不是真的让img的高度塌陷为0了,可以看到上图中img的黄色边框还是有正常高度的。如果给div里加点文字,效果如下:

可以看到,外层div在没有手动设定height的前提下,其高度是由内部content的最大高度决定的,由于img的float使得img具有高度塌陷的欺骗性,让div误以为img的line-height为0,因此div的高度就是文字的匿名inline-box的inline-height。

因此浮动并不是让元素的高度塌陷了,而是让元素具有高度塌陷的欺骗性。骗谁?骗别人!但骗不了自己,元素自身还是有高度的(见上图的黄框)。

回过头再看看浮动float的本意:让文字像流水一样环绕图片。重要的事情多看几遍...给div设定一个width:200px,并加点文字吧:

这就是浮动元素的本意。该效果是很难被其他CSS属性等价地模拟的。

但就像开头说的,CSS强大的灵活性使得很多CSS属性被用于了创造者都没想到的场景。以float为例,就被广泛用于了布局。是好是坏呢?不知道!西红柿臭鸡蛋先别急着扔。既然撸主不知道,还废话什么?先看看float布局的问题。渣浪微博改版前的好友列表用浮动布局,效果如下:

<ul>
    <li style="width:138px;margin:0 10px;text-align: center;float:left;">
        <div><img src="img/25/1.jpg" />尼古拉斯.旺财</div>
    </li>
    <li style="width:138px;margin:0 10px;text-align: center;float:left;">
        <div><img src="img/25/2.jpg" />功夫熊猫</div>
    </li>
    <li style="width:138px;margin:0 10px;text-align: center;float:left;">
        <div><img src="img/25/3.jpg" />月野兔</div>
    </li>
    <li style="width:138px;margin:0 10px;text-align: center;float:left;">
        <div><img src="img/25/4.jpg" />猫女郎</div>
    </li>
</ul>

每个li都设为浮动和定宽,实现了水平布局。但如果好友再长点呢?效果如下:

错行啦!常见的修正方案是手动设定一个高度,让文字固定显示一行,用裁掉超行文字的代价以避免错行问题。在撸主看来这就是让CSS属性用于不合原意处的局限性。设固定高度是OK,但如果哪天设计师觉得姓名需要显示两行呢,那固定高度就需要重新计算重新变。如果设计师觉得需要拓宽俄罗斯市场,姓名要显示三行呢?再把固定高度改大点。如果未来Boss脑袋一拍,咦,能不能高度自适应呢?由姓名最大高度的好友来决定每行的高度。你是不是会有准备一下简历的冲动?

当然现实没这么夸张,高度自适应是个烂大街的技术,将浮动float改成 display:inline-block 就行了,效果如下:

代码只需将上面float:left;替换成display: inline-block;,没对齐只需给li加上个vertical-align: top;(上面提到过,相比float,display:inline-block中间会有空隙,眼神好的可以从图中就能看出来,解决方案不是本篇的主题,可以问度娘)。这下高度自适应了,每行的高度都是以名字最长的高度为准。

回过头看用float来水平布局。是好是坏呢?好处是上手简单,随便什么程度的CSSer都能搞定。坏处是有时需要定高难以自适应。而display:inline-block;属性可是根正苗红的水平布局的属性,可以用其替代float。让float尽量多的干其本职工作:让文字像流水一般环绕浮动元素。所以撸主不知道答案。或许也根本没有正确答案,不停的推翻原有的认识和想法人才能进步。

PS:用浮动布局还有个坏处就是IE6下可能会有问题。但在IE6横行时期,撸主经验尚浅,现在项目里早已明确弃用IE6,撸主也懒得挖坟验证了。

清除浮动:

这个相对比较简单了。用clear即可。稍微要注意的是,clear是仅作用于当前元素,例如元素A是浮动元素,靠左显示。元素B是block元素紧跟在A后面。此时要清除浮动,是在B上设clear:left。你在A上设clear:right是没有用的,因为A的右边没有浮动元素。

但真这么简单吗?图样图森破。

先明确一个概念,用clear确实能达到我们期望的清除浮动的效果,这点没异议。但深入点看,究竟是清除了什么样的浮动呢?一图胜千言:

代码:(给页脚加上clear:left)

<div style="border:4px solid blue;">
    <div style="width:200px;border:4px solid red;float:left;">
        我是浮动元素1
    </div>
    <div style="width:200px;border:4px solid yellow;float:left;">
        我是浮动元素2
    </div>
</div>
<div style="border:4px solid gray;clear:left;">我是页脚</div>

因为浮动元素的高度欺骗性,导致外层div失去了高度(蓝色边框成了一条线)。为了让页脚显示到浮动元素下面,对页脚应用了clear:left。这是常规做法,没有任何新奇之处。但是外层div的高度仍旧处于塌陷状态,我们脑海真真正期望的清除浮动后的样子难道不是下面这样吗?

让清除浮动后,原本被欺骗的外层div获得正确的高度!借用文首大神链接的说法,我们脑中期望的其实并不是上图的清除浮动,而是下图的 闭合浮动

闭合浮动

闭合浮动的实现方法很多,常见的是最后增加一个清除浮动的子元素:

<div style="border:4px solid blue;">
    <div style="width:200px;border:4px solid red;float:left;">
        我是浮动元素1
    </div>
    <div style="width:200px;border:4px solid yellow;float:left;">
        我是浮动元素2
    </div>
    <div style="clear:both;"></div>  //加上空白div节点来闭合浮动
</div>
<div style="border:4px solid gray;">我是页脚</div>

缺点是会增加一个DOM节点。(话说当初撸主不知道在哪里看到这个做法时,作者并未讲这么做的原因,导致撸主不明白明明页脚加一个clear属性就能搞定的事,为何要大动干戈加一个DOM节点)

方法二:同样可以在最后增加一个清除浮动的br:将上面代码中<div style=”clear:both;”></div>替换成<br clear=”all” />即可。语义上比空的div标签稍微好一点,但同样会增加一个DOM节点。

方法三:父元素设置 overflow:hidden(如果你还要兼顾IE6的话,加上*zoom:1;来触发hasLayout)

<div style="border:4px solid blue;overflow:hidden;">
    <div style="width:200px;border:4px solid red;float:left;">
        我是浮动元素1
    </div>
    <div style="width:200px;border:4px solid yellow;float:left;">
        我是浮动元素2
    </div>
</div>
<div style="border:4px solid gray;">我是页脚</div>

这看起来很奇怪。因为子元素的浮动的高度欺骗,导致父元素误认为content高度为0(即蓝色边框为一条线),所以父元素设成overflow:hidden溢出隐藏的话,直觉上应该子元素由于溢出导致不显示才对,即整个页面只显示页脚。但实际效果,父元素设成overflow:hidden溢出隐藏后,竟然神奇地出现了闭合浮动的效果(蓝色边框正确获得了高度)。这是怎么回事呢?靠的是BFC,但BFC说起来又是很长一篇,先略过。你可以先简单地这么理解:浏览器厂商认为要让超出边框部分可以被修剪掉,那么前提就是父元素要正确获得高度,即父元素不能被欺骗导致高度塌陷。浏览器正确获得子元素的高度后给父元素重新设置高度。虽然权威解释肯定是BFC,但撸主这样理解了很久...

方法四:同上面将父元素设置 的overflow:hidden改成auto,不赘述

方法五:父元素也设成float。这样确实实现了闭合浮动,但页脚将上移,所以页脚仍旧需要clear:left。还有个缺点是由于浮动的包裹性,你确定父元素真的设成float对页面布局不会产生影响吗?

方法六:父元素设置display:table。效果OK,页脚也不需要设clear:left,但父元素的盒子模型被改变了,请先确认下这样的改动对页面布局不会产生影响吗?

方法七:用:after伪元素,思路是用:after元素在div后面插入一个隐藏文本”.”,隐藏文本用clear来实现闭合浮动:

.clearfix:after {
    clear: both;
    content: ".";   //你头可以改成其他任意文本如“abc”
    display: block;
    height: 0;      //高度为0且hidden让该文本彻底隐藏
    visibility: hidden;
}
.clearfix {
    *zoom: 1;
}
<div style="border:4px solid blue;" class="clearfix">
    <div style="width:200px; border:4px solid red; float:left;">
        我是浮动元素1
    </div>
    <div style="width:200px; border:4px solid yellow; float:left;">
        我是浮动元素2
    </div>
</div>
<div style="border:4px solid gray;">我是页脚</div>

这个方法很不错,就是相比上面的方法,理解起来稍微有一点点难度。但也仅增加一点点而已。

总结:

第一篇文章啰嗦几句。其实本文开头链接的几篇博文写的比我好,为何我要写这篇博文?是我自信能比大神们写的更好吗?当然不是。之所以写技术博文是因为这是一个非常好的学习总结的方式。就在写之前我仍旧以为已经非常了解float了,但真要提笔写,又发现自己在非常多的细节方面还是一知半解。只有真正静下心来,边思考边做demo验证边总结,才能将自己的知识总结成一篇博文。

技术博文不是散文,必须条理清晰,结构严谨,经得起推敲,不能满嘴跑火车,否则就误人子弟了。以前看优秀的文章时,偶尔会看到作者吐槽:这段话足足写了一下午。这篇文章写了三天三夜。看着文章字数又不多,最多10分钟就看完了,但如果你没有真正提笔写过,你可能体会不到期间的困难。

作为一个起步非常晚的前端工程师(I know…I late to the Party.)我只能死磕自己。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 问答题47 /72 常见浏览器兼容性问题与解决方案? 参考答案 (1)浏览器兼容问题一:不同浏览器的标签默认的外补...
    _Yfling阅读 13,728评论 1 92
  • 1. 居中不定高div样式 参考:http://www.haorooms.com/post/css_div_juz...
    darr250阅读 4,635评论 0 7
  • <a name='html'>HTML</a> Doctype作用?标准模式与兼容模式各有什么区别? (1)、<...
    clark124阅读 3,456评论 1 19
  • 前端基础之CSS CSS语法 CSS 规则由两个主要的部分构成:选择器,以及一条或多条声明。 例如: CSS的四种...
    lkning阅读 584评论 0 2
  • 学习 初中,我用了两年时间,颓废,直到初三才认真读书。最后考上县重点高中。 高中,同样用了差不多两年时间,到了高三...
    Randylee阅读 213评论 1 1