CSS浮动float详解

   <p style="text-align:center"><img src="https://simg.open-open.com/show/28fed4b0284462c3f1b9003c5c03e59a.png"></p>    <p>CSS里浮动float是个概念比较暧昧的属性,撸主最早对浮动float的认识是基于布局的,认为float元素就是用于: “让block元素无视float元素,让inline元素让流水一样围绕着float元素” 来实现浮动布局。现在想想,当初真是图样图森破。</p>    <p>其实这个属性撸主一直是比较模糊的,感觉似懂非懂。本着和自己死磕的精神,在参考了许多大神的博文后,将我的理解整理归纳在本文中,希望能可以帮助到你。当然撸主水平有限,如有错误敬请指出。</p>    <p>以下是网上大神关于float的优秀文章:</p>    <p><a href="/misc/goto?guid=4959642470178478664" rel="nofollow,noindex">CSS浮动(float,clear)通俗讲解</a></p>    <p><a href="/misc/goto?guid=4959642470249400908" rel="nofollow,noindex">CSS float浮动的深入研究、详解及拓展(一)</a></p>    <p><a href="/misc/goto?guid=4959642470333866126" rel="nofollow,noindex">CSS float浮动的深入研究、详解及拓展(二)</a></p>    <p><a href="/misc/goto?guid=4959642470504279789" rel="nofollow,noindex">那些年我们一起清除过的浮动</a></p>    <h3>浮动float的本意:</h3>    <p>传统如C++,Java等编程语言一个API可能只能对应做一件事,即使有了模板和泛型编程,通常也只能做某一类事。但CSS是门相当灵活的语言。某个CSS属性被用于的场景,可能会完全违背当初创造该CSS属性的本意。在CSS的世界里,想实现某个效果,会有很多方法。那究竟选择哪种方法呢?有很多判断标准,如重绘,如回流,如极简主义。撸主也有一个不成熟的判断标准就是: 根据该CSS属性被创造时的本意,该用哪个属性就用哪个属性。</p>    <p>那浮动float的本意是什么呢?是: <strong>让文字像流水一样环绕浮动元素。</strong></p>    <p>怎样才能实现该效果呢?用 <strong>包裹性</strong> 和 <strong>高度欺骗</strong></p>    <h3>特性一:包裹性</h3>    <p>例1:首先来看浮动float的包裹性,所谓一图胜千言:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/37cde8bb3f848a7f293326b2807149ce.jpg"></p>    <p>相关代码非常简单:</p>    <pre>  <code class="language-css"><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></code></pre>    <p>所谓包裹性一目了然。block元素不指定width的话,默认是100%,一旦让该div浮动起来,立刻会像inline元素一样产生包裹性,宽度会跟随内容自适应。(这也是通常float元素需要手动指定width的原因)</p>    <p>再加上一个div的话,效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/d87cd098d54357b20371e4d8c01f6db6.jpg"></p>    <pre>  <code class="language-css"><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></code></pre>    <p>效果非常近似于display:inline-block。但相比之下,浮动能设定为左浮和右浮,但display:inline-block都是从左到右排列的。(还有些细微差别,两个display:inline-block间会有空隙,但两个float间没有。这不是本篇的主题,暂时略过)</p>    <h3>特性二:高度欺骗</h3>    <p>(首先声明:其实是CSS层级在起作用,但CSS层级适合单独写一篇,内容实在太多,不适合在这里展开,就理解为高度欺骗吧)</p>    <p>例1中浮动float被设在了外围div上,因此高度欺骗性没体现出来。现在给内层img元素设定float。所谓一图胜千言:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/708481a6f6cb6d24269c3d9f7fea22a9.jpg"></p>    <pre>  <code class="language-css"><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></code></pre>    <p>和例子1唯一的区别就是:将外层div的float移到内层img中。这下高度欺骗性体现出来了。例1中给外层div加上浮动,因此外层div会有包裹性,其内容是img图片,所以可以看到红色边框包裹着img。</p>    <p>例2中外层div没有了浮动,因此红色边框宽度默认是100%全屏。其内容img由于加上了float,使得该img具有了欺骗性。float给img施了个障眼法,让该img的inline-height高度塌陷为0了。这样外层div计算高度时,认为img的高度为0,相当于div的content的高度为0,因此红色边框看起来是一条直线。</p>    <p>但请注意障眼法毕竟是障眼法,并不是真的让img的高度塌陷为0了,可以看到上图中img的黄色边框还是有正常高度的。如果给div里加点文字,效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/11f3b85682475913f8be5a4137067ddf.jpg"></p>    <p>可以看到,外层div在没有手动设定height的前提下,其高度是由内部content的最大高度决定的,由于img的float使得img具有高度塌陷的欺骗性,让div误以为img的line-height为0,因此div的高度就是文字的匿名inline-box的inline-height。</p>    <p>因此浮动并不是让元素的高度塌陷了,而是让元素具有高度塌陷的欺骗性。骗谁?骗别人!但骗不了自己,元素自身还是有高度的(见上图的黄框)。</p>    <p>回过头再看看浮动float的本意:让文字像流水一样环绕图片。重要的事情多看几遍...给div设定一个width:200px,并加点文字吧:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4e0333f18405699de7c3688ff352e699.jpg"></p>    <p>这就是浮动元素的本意。该效果是很难被其他CSS属性等价地模拟的。</p>    <p>但就像开头说的,CSS强大的灵活性使得很多CSS属性被用于了创造者都没想到的场景。以float为例,就被广泛用于了布局。是好是坏呢?不知道!西红柿臭鸡蛋先别急着扔。既然撸主不知道,还废话什么?先看看float布局的问题。渣浪微博改版前的好友列表用浮动布局,效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5b56fcf473db2abf13e0a1949d8e0a3c.jpg"></p>    <pre>  <code class="language-css"><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></code></pre>    <p>每个li都设为浮动和定宽,实现了水平布局。但如果好友再长点呢?效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/ceb6a006e8e39606ae9de2b9b91f63cd.jpg"></p>    <p>错行啦!常见的修正方案是手动设定一个高度,让文字固定显示一行,用裁掉超行文字的代价以避免错行问题。在撸主看来这就是让CSS属性用于不合原意处的局限性。设固定高度是OK,但如果哪天设计师觉得姓名需要显示两行呢,那固定高度就需要重新计算重新变。如果设计师觉得需要拓宽俄罗斯市场,姓名要显示三行呢?再把固定高度改大点。如果未来Boss脑袋一拍,咦,能不能高度自适应呢?由姓名最大高度的好友来决定每行的高度。你是不是会有准备一下简历的冲动?</p>    <p>当然现实没这么夸张,高度自适应是个烂大街的技术,将浮动float改成 <strong>display:inline-block</strong> 就行了,效果如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/3eda89e7639185c03ee8edaffb6eff49.jpg"></p>    <p>代码只需将上面float:left;替换成display: inline-block;,没对齐只需给li加上个vertical-align: top;(上面提到过,相比float,display:inline-block中间会有空隙,眼神好的可以从图中就能看出来,解决方案不是本篇的主题,可以问度娘)。这下高度自适应了,每行的高度都是以名字最长的高度为准。</p>    <p>回过头看用float来水平布局。是好是坏呢?好处是上手简单,随便什么程度的CSSer都能搞定。坏处是有时需要定高难以自适应。而display:inline-block;属性可是根正苗红的水平布局的属性,可以用其替代float。让float尽量多的干其本职工作: <strong>让文字像流水一般环绕浮动元素</strong> 。所以撸主不知道答案。或许也根本没有正确答案,不停的推翻原有的认识和想法人才能进步。</p>    <p>PS:用浮动布局还有个坏处就是IE6下可能会有问题。但在IE6横行时期,撸主经验尚浅,现在项目里早已明确弃用IE6,撸主也懒得挖坟验证了。</p>    <h3>清除浮动:</h3>    <p>这个相对比较简单了。用clear即可。稍微要注意的是,clear是仅作用于当前元素,例如元素A是浮动元素,靠左显示。元素B是block元素紧跟在A后面。此时要清除浮动,是在B上设clear:left。你在A上设clear:right是没有用的,因为A的右边没有浮动元素。</p>    <p>但真这么简单吗?图样图森破。</p>    <p>先明确一个概念,用clear确实能达到我们期望的清除浮动的效果,这点没异议。但深入点看,究竟是清除了什么样的浮动呢?一图胜千言:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0298e75735e412c8dfe7ba5d2277c254.jpg"></p>    <p>代码:(给页脚加上clear:left)</p>    <pre>  <code class="language-css"><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></code></pre>    <p>因为浮动元素的高度欺骗性,导致外层div失去了高度(蓝色边框成了一条线)。为了让页脚显示到浮动元素下面,对页脚应用了clear:left。这是常规做法,没有任何新奇之处。但是外层div的高度仍旧处于塌陷状态,我们脑海真真正期望的清除浮动后的样子难道不是下面这样吗?</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c515e1a03293ede501a1474355ad3139.jpg"></p>    <p>让清除浮动后,原本被欺骗的外层div获得正确的高度!借用文首大神链接的说法,我们脑中期望的其实并不是上图的清除浮动,而是下图的 <strong>闭合浮动</strong> 。</p>    <h3>闭合浮动</h3>    <p>闭合浮动的实现方法很多,常见的是最后增加一个清除浮动的子元素:</p>    <pre>  <code class="language-css"><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></code></pre>    <p>缺点是会增加一个DOM节点。(话说当初撸主不知道在哪里看到这个做法时,作者并未讲这么做的原因,导致撸主不明白明明页脚加一个clear属性就能搞定的事,为何要大动干戈加一个DOM节点)</p>    <p>方法二:同样可以在最后增加一个清除浮动的br:将上面代码中 <div style=”clear:both;”></div> 替换成 <br clear=”all” /> 即可。语义上比空的div标签稍微好一点,但同样会增加一个DOM节点。</p>    <p>方法三:父元素设置 overflow:hidden(如果你还要兼顾IE6的话,加上*zoom:1;来触发hasLayout)</p>    <pre>  <code class="language-css"><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></code></pre>    <p>这看起来很奇怪。因为子元素的浮动的高度欺骗,导致父元素误认为content高度为0(即蓝色边框为一条线),所以父元素设成overflow:hidden溢出隐藏的话,直觉上应该子元素由于溢出导致不显示才对,即整个页面只显示页脚。但实际效果,父元素设成overflow:hidden溢出隐藏后,竟然神奇地出现了闭合浮动的效果(蓝色边框正确获得了高度)。这是怎么回事呢?靠的是BFC,但BFC说起来又是很长一篇,先略过。你可以先简单地这么理解:浏览器厂商认为要让超出边框部分可以被修剪掉,那么前提就是父元素要正确获得高度,即父元素不能被欺骗导致高度塌陷。浏览器正确获得子元素的高度后给父元素重新设置高度。虽然权威解释肯定是BFC,但撸主这样理解了很久...</p>    <p>方法四:同上面将父元素设置 的overflow:hidden改成auto,不赘述</p>    <p>方法五:父元素也设成float。这样确实实现了闭合浮动,但页脚将上移,所以页脚仍旧需要clear:left。还有个缺点是由于浮动的包裹性,你确定父元素真的设成float对页面布局不会产生影响吗?</p>    <p>方法六:父元素设置display:table。效果OK,页脚也不需要设clear:left,但父元素的盒子模型被改变了,请先确认下这样的改动对页面布局不会产生影响吗?</p>    <p>方法七:用:after伪元素,思路是用:after元素在div后面插入一个隐藏文本”.”,隐藏文本用clear来实现闭合浮动:</p>    <pre>  <code class="language-css">.clearfix:after {      clear: both;      content: ".";   //你头可以改成其他任意文本如“abc”      display: block;      height: 0;      //高度为0且hidden让该文本彻底隐藏      visibility: hidden;  }  .clearfix {      *zoom: 1;  }</code></pre>    <pre>  <code class="language-css"><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></code></pre>    <p>这个方法很不错,就是相比上面的方法,理解起来稍微有一点点难度。但也仅增加一点点而已。</p>    <h3>总结:</h3>    <p>第一篇文章啰嗦几句。其实本文开头链接的几篇博文写的比我好,为何我要写这篇博文?是我自信能比大神们写的更好吗?当然不是。之所以写技术博文是因为这是一个非常好的学习总结的方式。就在写之前我仍旧以为已经非常了解float了,但真要提笔写,又发现自己在非常多的细节方面还是一知半解。只有真正静下心来,边思考边做demo验证边总结,才能将自己的知识总结成一篇博文。</p>    <p>技术博文不是散文,必须条理清晰,结构严谨,经得起推敲,不能满嘴跑火车,否则就误人子弟了。以前看优秀的文章时,偶尔会看到作者吐槽:这段话足足写了一下午。这篇文章写了三天三夜。看着文章字数又不多,最多10分钟就看完了,但如果你没有真正提笔写过,你可能体会不到期间的困难。</p>    <p>作为一个起步非常晚的前端工程师(I know…I late to the Party.)我只能死磕自己。</p>    <p> </p>    <p>来自:http://www.jianshu.com/p/07eb19957991</p>    <p> </p>