浮动框就是一个框在当前行被向左或向右挪动(偏移),它不在常规流中。
1. 浮动框的位置
一个浮动框,会被向左或向右偏移,直到它的外边界( outer edge,又叫margin edge ) 接触到它包含块的边界或另一个浮动元素的外边界 ,如果存在一个行框,那么浮动框的顶边会和当前行框的顶部对齐,行框内该浮动框后面的内容将会紧接在浮动框前面的行内内容显示,因为该浮动框已经被抽离出常规流了。下面一个例子综合了几种浮动块定位的情况:
<html> <head> <style type="text/css"> div, img.left { height:50px; width:50px; float:left;} img.right {height:50px; width:50px; float:right;} span {float:left;font-size:20px; border:solid;} </style> </head> <body> <p> <div><img src="/i/eg_cute.gif" /></div> This is some text. This is some text. This is some text.This is some text. <img class='left' src="/i/eg_cute.gif" /> <img class='right' src="/i/eg_cute.gif" /> This is some text. This is some text. This is some text.This is some text.This is some text. This is some text.This is some text. This is some text. This is some text.<span>Float inline</span>This is some text. This is some text. This is some text.This is some text. This is some text. This is some text.This is some text. This is some text. </p> </body> </html>
如图,第一张图片向左偏移直到它包含块的左上边界,第二三张图片分别向左右偏移,它们的上界是所处行框的顶部。第二张图片向左偏移的 过程中遇到了第一个浮动块的右边,停止移动,第三张图片则一直移到包含块的右边界。行内文字浮动到左边的过程中没有碰到任何浮动块,所以一直移到了左边界。当前行里浮动文字前的内容,都被重新排列到该浮动的右侧。
css specification里对浮动的实现列出了很多规则,大体上就是本文第二句话的各种扩展。值得注意的有两条:
- 浮动框要放置得尽可能的高。
对于更高和更左/右,优先选择前者。
<html> <head> <style type="text/css"> div{ width:200px;} img#left1 { height:100px; width:70px; float:left;} img#left2 { height:50px; width:50px; float:left;} img#left3 { height:100px; width:100px; float:left;} </style> </head> <body> <div> <img id='left1' src="/i/eg_cute.gif" /> <img id='left2' src="/i/eg_cute.gif" /> <img id='left3' src="/i/eg_cute.gif" /> </div> </body> </html>
第三个浮动框会优先往上,贴着块二的下外边,再尽量往左靠。
- 浮动框的顶边不可以高于源文档中先前元素产生的块框或浮动框的顶
<html> <head> <style type="text/css"> p { width:90px;border:solid;overflow:hidden;} img.left { height:50px; width:50px; float:left;} img.right { height:30px; width:30px; float:right;} </style> </head> <body> <p> <img class='left' src="/i/eg_cute.gif" /> <img class='left' src="/i/eg_cute.gif" /> <img class='right' src="/i/eg_cute.gif" /> </p> </body> </html>
虽然上一条规则说明了浮动块会优先往上浮,但是它不可以高过在它之前生成的浮动框的顶。所以尽管上方有空间容纳“right”浮动块,但是它最高也只能浮动到与前一个“left”浮动块的顶平齐。
2. 浮动框对行框的影响
浮动框脱离了常规流,所以在该浮动框之前或之后创建的非定位块框照常垂直排列,就好象浮动框并不存在一样。但是,浮动框之后创建的行框会被缩短,以便为浮动元素提供空间。如果被缩短的行框无法容纳一段的内容,它将会向下移动,直到有找到足够的空间或没有更多的浮动元素为止。
<html> <head> <style type="text/css"> div#fl { float:left; width:100px; height:100px; margin:10px; border:1px solid black; text-align:center;} div#ct { width:300px; height:150px; border:2px solid red;} </style> </head> <body> <div id='fl'> <img src="/i/eg_cute.gif" /> </div> <div id='ct'> <img src="/i/eg_cute.gif" />hahahahahahahahahaha </div> </body> </html>
可以看到fl元素之后创建的ct块就像fl不存在一样排列在包含块的左上角。但是ct块中处在浮动框右面的行框被缩短了,所以行内元素图片被放置在了浮动元素的右边,也是行框的最左边。如果一个行框的长度无法容下超过其长度的元素,那么它会一直往下一直找到可以容下该元素的行框(或是块框内最大的行框也无法容下就只好溢出)。如上所示,只有到离开浮动块影响范围,行框长度恢复正常时才有了足够的空间放下。
3. clear属性
有时候我们不希望行框围绕着浮动框,或是希望浮动框后的创建的块框不要忽视浮动框的存在,从而实现某些特定的布局。这时候clear属性可以帮我们实现这一目的。
- clear:left、right、both:分别规定指定元素的左边、右边、两边不会与先前的浮动框相邻。
即如果设置clear:left,那么该元素(非float元素)的上border edge(注意是border)必须在之前生成的所有左浮动元素的bottom margin edge(注意是margin)之下。如果设置clear:both,那么该元素的top border edge必须在之前创建的所有浮动框的bottom margin edge之下。 如果指定该属性的是一个浮动元素,那么它的top margin edge低于相应的浮动框的bottom margin edge。
当该属性设置为以上三种值的时候,将会引入clearance的概念。
- clearance:阻止了外边距的合并,就像是在元素的外边框上方插入了一个空白,同时通过调整为特定的大小(可能为负)使得该元素被垂直推动到相应的位置。例如:
<html> <head> <style type="text/css"> * { margin:0; padding:0; border:0;} #d1 { width:50px; height:50px; margin :10px; background-color:red;} #d2 { width:50px; height:50px; margin :10px; background-color:blue; clear:both;} #fl { width:50px; height:50px; margin :10px; background-color:green; float:left;} </style> </head> <body> <div id="d1">d1</div> <div id="fl">fl</div> <div id="d2">d2</div> </body> </html>
如上图所示,浮动元素的外边距不会与其他元素的外边距合并,所以d1和fl中间间隔20px。因为d2设置了clear属性值为both,所以d2的上border edge与fl的下bottom edge齐平,fl和d2之前间隔为fl的外边距10px。
clearance的值就是没设置clear属性且外边距不发生合并时两个元素之间的垂直距离,与设置了clear属性后该两个元素见的实际垂直距离的差值。对于上述例子来说,如果没有设置clear属性,且没有外边距合并,d1与d2元素border edge间距离为margin d1+ margin d2=20px,设置clear=both后,间距为 margin d1+ margin fl + height fl + margin fl = 80px, 所以clearance = 80px - 20px = 60px。
clearance也可能为负值。如上述计算中若margin fl = 0,则clearance = height fl - margin d2, 当浮动元素的高度小于d2的下外边距时,clearance的值为负。
clear属性既可以实现同一个方向的连续的float元素垂直排列的效果,也可以使得紧跟在float元素后的块元素放置在该浮动元素的下方,不会被float元素覆盖。clear 另一个重要作用如下:
对于一个常规流中的块元素,如果其中只包含浮动子元素,且块的height值为auto(即没有指定该元素的具体高度),那么该块的高度为0。因为float元素不在常规流中,相当于该元素没有任何内容。
<html> <head> <style type="text/css"> * { margin:0; padding:0; border:0;} #container { border:solid 1px;} .d1 { width:50px; height:50px; margin :10px; background-color:red;float:left;} </style> </head> <body> <div id='container'> <div class="d1"></div> <div class="d1"></div> </div> </body> </html>
如上所示,带边框的包含块只显示成了一条线。这样的话应用与父元素的一些属性像是下外边距,背景图片等都将失去效果。此时,如果我们为包含块增加一个常规流中的子元素,并且为其设置clear属性,那么就可以“撑开”该父元素了。
<html> <head> <style type="text/css"> * { margin:0; padding:0; border:0;} #container { border:solid 1px;} .d1 { width:50px; height:50px; margin :10px; background-color:red;float:left;} .foot { clear:both;} </style> </head> <body> <div id='container'> <div class="d1"></div> <div class="d1"></div> <div class="foot"></div> </div> </body> </html>
因为此时所有浮动元素的下方会被插入一个空的常规流中的元素,父块可以识别该元素并且自动调整自己的高度来包含该空元素。
上述方法中更流行一种写法的是直接通过css伪元素来为父元素的最后添加一个空元素
#container:after{clear:both; display:block; content:'';}
4. 浮动清除
除了上述的添加空元素的方法来清楚浮动,还有一些方法可以实现同样的效果
- 将父元素也设置成浮动元素
#container{border:solid 1px;float:left;}
但这样的话会对其后面的元素的定位产生影响。所以有些站点(W3School)选择对布局中的所有元素浮动,然后使用适当的有意义的元素(常常是站点的页脚)对这些浮动进行清理。
- 使用overflow属性
#container{border:solid 1px;overflow:auto;}效果与使用带clear属性的空元素一样。原理在前面的 CSS定位之常规流 一文里已经写过了,因为产生了一个新的block formatting context,会包含其内所有的浮动元素。但是缺点是,如果子元素过大时,可能会产生我们并不想要的滚动条。
<html> <head> <style type="text/css"> * { margin:0; padding:0; border:0;} #container { border:solid 1px;overflow:auto;} .d1 { width:1200px; height:50px; margin :10px; background-color:red;float:left;} </style> </head> <body> <div id='container'> <div class="d1"></div> </div> </body> </html>
5. overflow属性的另一个用法
overflow属性设置了当对象的内容超过其指定高度及宽度时如何显示。
- visible:默认值,不剪切内容也不添加滚动条
- auto:在必需时,对象内容才会被剪切或添加滚动条
- hidden:不显示超过对象尺寸的内容
- scroll:总是显示滚动条
当设置成非visible属性时,将建立一个新的block formatting context。所以如果不希望浮动元素之后元素的文本内容环绕在浮动元素的周围,可以通过设置其overflow属性来实现。
例如修改第二节中的例子,给div#ct添加overflow:auto;。那么结果将会有所不同。
浮动元素后的块元素不再无视浮动元素的存在了。原因就是block formatting context不会包含非子元素的浮动元素。
css specification中原话如下:
The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space.