浮动 三 再见,浮动!

181 阅读6分钟

作为终结篇,竟然是消灭它。。。

好吧,还是先开始吧。

一. clear属性

说道清除浮动,大家恐怕第一个想到的就是clear属性吧。该属性的官方说明如下:

属性名: clear
值: none | left | right | both | inherit
初始值: none
继承性: 无
应用对象:block-level元素

它指明了block-level box(看第21条)不希望自己的 left/ right / both与前面的float box相毗邻。要注意的是,这里清除的是排在block-level box前面的float box,与后面的float box不相干啊。有疑惑的童鞋请翻翻这篇文章的上半部分。

  • 设为 left 会使得该box的上边框边缘(top border edge)不高于在它之前的任何向左浮动的float box的下边缘(看第24条)
  • 设为 right 会使得该box的上边框边缘(top border edge)不高于在它之前的任何向右浮动的float box的下边缘
  • 设为 both 会使得该box的上边框边缘(top border edge)不高于在它之前的任何float box的下边缘
  • 设为 none 那就是啥也不做


以上这些都是我们通过代码调节可以直观看见的现象,实际背后有更深层的东西值得我们去挖掘。

二. “清除”引入的条件、“清除”达到的效果、清除公式

1. 条件

首先问个问题: 是不是只要clearence设为非none,就真的会发生浮动清除呢?

当然不是!

如果clearence设为非none, css可能会引入清除。决定是否引入还得看block-level box在没有设置clearence(或者说clearence为none)的情况下所处的位置。

假设block-level box的clearence设为left。现在重置它的clearence为none,看看它的上边框边缘是否高于它之前的任何向左浮动的float box的下边缘。如果高于,则引入清除。

2. 效果

看过前几篇浮动的文章的童鞋都知道,float box可能会与block-level box并排,产生“围绕现象”。那么清除浮动带来的效果就是 block-level box会流动到float box之下,若block-level box与其他box产生了margin重叠, 重叠现象也会消失。

对比一下,或许更清楚!

例一 无清除

  1. <html>
      <head>
      <style type="text/css">	
    	.parent{
    		width:500px;
    		height:auto;
    		margin:20px auto 0;
    		padding:10px;
    		line-height:30px;
    		font-family:"Times New Roman",Georgia,Serif;
    		border:solid 2px rgba(247, 79, 79, 0.56);
    	}
    	.float-child{
    		width:100px;
    		height:50px;
    		float:left;
    		margin-right:10px;
    		box-sizing:border-box;
    		background:rgba(247, 79, 79, 0.56);
    	}	
    	.normal-child{
    		width:350px;
    		border:solid 1px rgba(247, 79, 79, 0.56);
    		margin-bottom:5px;
    		padding-left:5px;
    	}
    	.first-block{
    		margin-bottom:10px;
    	}
    	.second-block{
    		margin-top:20px;
    	}
      </style>
      </head>
    <body>
      <div class='parent'>
        <div class='normal-child first-block'>first block-level box</div>
        <div class='float-child'></div>
    	<div class='normal-child second-block'>second block-level box</div>
      </div>
    </body>
    </html>
    
    chrome上的效果:


float box看上去完全就是一个土匪嘛,很霸道的挡住第二个block-level box!

另外,第一个block-level box与第二个block-level box也产生了margin重叠,看个像素图。

可以看到,第一个block-level box与第二个block-level box之间的距离取margin的最大值20px,它们的margin发生了重叠。

再去看看清除带来的变化。

例二 引入清除

在例一的基础上修改.second-block类,具体如下:

.second-block{
		margin-top:20px;
                clear:left;
	}

登登登~~~“清除”上场,效果杠杠滴!

第二个block-level box不仅成功的摆脱了float 土匪,还与第一个block-level box划清了界限,margin没有重叠,互不干扰,清的很干净嘛!

由此,可看出清除就如同在block-level box的上方加了一定高度的空白,这会使得block-level box移动到float box之下,并阻止了margin重叠。

看到这,有木有童鞋对block-level box下移的计算过程感兴趣?虽说在实际编程中没啥用处,但是可以在面试官面前装大神。。。。好吧,我接着讲了,不感兴趣的童鞋直接略过下节。

3. 清除公式

用过清除的都知道,block-level box虽说会移动到float box下方,但也不是随意下移的,它每次都会保证border的上边缘与位置最低的被清除float box的下边缘齐平。这是如何做到的呢?计算出block-level box的上边缘与位置最低的被清除float box的下边缘齐平所需要的清除距离(设为C),然后将block-level box下移C。

距离又是怎么算出来的呢?这里有个清除公式。

假设在html文档里有如下几个元素:第一位是margin-bottom为M1的block B1,第二位是高度为H的float box,第三位是margin-top为M2的block B2。B1和B2均没有子box,也没有设置padding或border。另外,B2不为空,且clear为both。那么它们在浏览器上应该表现成酱紫:

因为要引入清除,那么第二个block box必须满足:上边框边缘高于它之前的任何向左浮动的float box的下边缘,也就是:

max(M1,M2) < M1 + H

看上文,我们知道:清除需要保证B2的border的上边缘与位置最低的被清除float box的下边缘齐平,也就是:

F的下边缘 = B2的border的上边缘

M1 + H = M1 + C + M2 (注:M1和M2此时是不会重叠的)

C = M1 + H - M1 - M2

= H - M2

由此,我们知道清除距离

C = H - M2

也许有爱思考的童鞋问道:如果float box有上下margin怎么办?

此时的C = (H + 上margin + 下margin) - M2。

为啥?哈哈,这是因为float box不会与任何box发生margin重叠,所以呢,在有上下margin时得加上margin。

是不是没啥鸟用,^ ^ ~~~

三. 大家口中的清除

常看到某些博文写到,如何清除box内的浮动,清除浮动的N种方法,balabala......一大堆。实际上标准的清除浮动只能清除float box下面的第一个block-level box。

为什么会想到要清除box内的浮动?我想大概是因为某个block box的子float box跑到该block box的外面去了,一些童鞋以为是浮动搞得鬼。

其实这不完全怪浮动。

每个box的高度计算是要遵循一定的规则。overflow为visible,height为auto的block box在计算高度时会忽略子box中的float box的高度,由此造成float box的下边缘跑到block box之外。

还有类似清除浮动的N种方法,大部分是不明白这里面的规则而写的hack方法,这些奇怪的清除方式常常会产生一些不易察觉的bug,大家还是少用为妙。知道背后的机制,再给出正确的解决办法,才是终极之道啊!

浮动终于终于终于写完了,真是大头啊,花了不少时间整理。接下来要去啃下一个大骨头了,byebye啦。

ps: 本文中的例子均是在chrome 49.0上测试。