代码改变世界

Containing Floats 包含浮动

2014-07-28 23:40  Jeff Ma  阅读(849)  评论(0编辑  收藏  举报
 
正因为浮动功能强大,而且很有用,所以常被用作布局的技巧工具。你可能看到过图1中的情形,这是仅由两个div元素实现的,每个div中有一个浮动的图片。
图1. 那是不正确的
 
这可能不是作者的意图,但是考虑到所使用的样式,这是正确的布局啊。我们是这样创建的:
div.item {border: 1px solid; padding: 5px;}
div.item img {float: left; margin: 5px;}
以上是所有的样式。在图1中看到的结果是因为div元素没有“拉伸”以包含住其中的浮动图片。从另外的角度来看,出现这种情况是因为浮动元素“伸出”了div元素的底部。
 
这不是一个bug,也不是CSS的缺陷。事实上,许多作者大部分情况下想要这种伸出的行为。仅仅在图1中显示的例子不是他们想要的。
 
理解问题
那什么时候作者想要浮动伸出包含元素的效果时被认为是正确的呢?很简单:从历史上看最常见的使用浮动的情况是什么。考虑下图2和生成此效果的基本标记结构。
图2. 浮动图片,流动文本
<p>
 ...text...
 <img src="jul31-03-sm.jpg" height="200" border="0" class="picture">
 ...text...
</p>
<p>
 ...text...
</p>
将流动的文本环绕在图片周围这种实践可追溯到很久以前。这就是从Netscape1.1开始将这种能力添加到Web的原因,也是CSS使用属性float使其成为可能的原因。但是再仔细看看图2。浮动图片伸出了包含它的元素。我们通过给段落添加边框可以看得更清楚,如图3所示。
图3.在段落上添加边框
所以现在我们知道了浮动元素伸出包含它们的元素为什么是重要的了。如果不伸出,图2将是图4的样子。
图4. 如果浮动元素扩展它们的父元素
 
这将是设计者不能够接受的。所以,为了保留Web设计的传统和作者的期望,CSS被设计成允许浮动元素伸出包含它们的元素的底部。虽然这对于一般的文本流是必须的,但主要问题出现在把浮动用于布局用途的时候。
 
清除解决方案
 
如果浮动被用在非表格布局中,那么需要某种方式让包含它们的元素拉伸以包含住它们。目前,需要一点结构性的hack。既然我们要在包含元素的底部放一个元素来清除以前浮动的底部,clear是我们的答案。我们仅需要在容器结束之前插入一个块级元素,并清除浮动。考虑:
<div class="item">
 <img src="w6144.gif">
 Widget 6144
 <br>$39.95
 <hr>
</div>
<div class="item">
 <img src="w6145.gif">
 Widget 6145
 <br>$44.95
 <hr>
</div>
现在我们将以下规则应用到前面的标记上,得到图5的效果。

div.item hr {display: block; clear: left; margin: -0.66em 0;
  visibility: hidden;}
图5 使用水平规则强制扩展
 
通过确保hr元素是块级的,又是正常流的一部分,而且清除了浮动,我们强制div“拉伸包含住”左浮动的图片。
 
负数的顶部和底部margin一般产生关闭hr占用的空间的效果。然而,这不是精度的,而且浏览器之间也不尽相同。水平规则的半神秘性使得很难确切预测将会出现什么状况。hr的有效高度可能是0,或者一个小正数,或者甚至是一个负数高度。
 
因此,在需要精确清除效果的情况下,作者可以使用div取代hr来创建清除效果。例如:
div.clearer {clear: left; line-height: 0; height: 0;}

<div class="item">
 <img src="w6144.gif">
 Widget 6144
 <br>$39.95
 <div class="clearer">&nbsp;</div>
</div>
设置Float来修复Float
 
有一种方式可以避免过度使用到现在为止讨论过的结构性hack,虽然这些结构性hack有时候仍然是必要的。在大多数浏览器中,正如CSS2.1中所定义的,浮动元素会扩展以便包含任何从它遗传的浮动元素。所以在小产品例子中,我们可以移除“clearer”元素,使用这些风格替代:
div.item {float: left; border: 1px solid; padding: 5px; width: 60%;}
div.item img {float: left; margin: 5px;}
注意我们浮动了图片和“item”div。通过设置div的宽度超高50%,我们确保div不会出现在同一行,而是垂直地堆积在一起。效果如图6。
图6 使用浮动实现拉伸以包含住浮动元素。
就标记和风格而言,很明显这样管理起来更简单了。然而,到现在为止讨论过的hack仍然是有用的。假设你想在商品的下面放些建议文本。为了让文本不流到商品的右边,我们需要插入清除hack。这会引导我们创建如下标记,如图7所示。

<div class="item">
 <img src="w6144.gif">
 Widget 6144
 <br>$39.95
</div>
<div class="item">
 <img src="w6145.gif">
 Widget 6145
 <br>$44.95
</div>
 <div class="clearer">&nbsp;</div>
 <p>Widgets are sold on an "as is" basis without
    warranty or guarantee.</p>

图7 浮动加hack实现想要的布局
起清除作用的div有效地将正常流推下来,强制任何后面的内容跟在被清除元素后面,因此跟在浮动div后面。
使用浮动包含浮动的潜在缺陷是依赖浏览器对多层嵌套的浮动元素的布局的一致解释。如果这些浮动元素是更复杂布局的一部分,情况变得更脆弱,该部件可能使用了浮动,定位或表格。这不是说这些布局不可能实现。然而,他们可能涉及大量的试验和错误,避免晦涩浮动和其他可能潜藏在渲染引擎内部的布局 bug。
总结
通过理解浮动和正常流之间的相互联系,理解清除可用来处理浮动周围的正常流,作者可以把浮动当作一个非常强大的布局工具。由于浮动最初不是用于布局,为了让它们达到预期有些hack可能是必要的。这可能涉及包含浮动的浮动元素,“清除”元素,或者两者的结合。
展望未来,已有各种提议要增强CSS,允许作者声明一个元素拉伸以包含住其中的任何浮动元素。很明显将这种能力添加到CSS是受欢迎的,但是截止到本文撰写时,还没有添加这种能力,对这种能力的支持可能还需要很长一段时间。

源代码 https://files.cnblogs.com/jeffma/code.rar