CSS浮动布局与inline-block
2010 11 13 04:36 PM 5165次查看
有些见解和其作者张鑫旭不同,因此这里我总结并阐述一下自己的看法。为了避免太复杂,我不会对不符合标准的IE浏览器进行hack处理。
首先要说的是浮动(float)的作用。
看报纸时,经常会看到文字环绕图片的排版方式,这样节省了排版空间,让内容更加紧凑,不会让图像过于突兀。而在网页排版时,想达到相同效果的话,就只能将图片设为浮动元素了,这便是float诞生的初衷。
可在大家抛弃table布局后,便渐渐发现横向排列元素非常麻烦了,想要自适应宽度得费老大劲了。而引入浮动后,元素就会自动紧贴着排列成一行了,而且适应性还不错。然而这种用法有个很严重的问题:如果不清除浮动的话,后续的元素仍会与其并排。
当然也别忘了float:right,在需要元素右对齐时,text-align:right通常都要在外面套一层,显得没那么干净。
这大概就是float的主要用处了吧,与负边距的搭配就不说了=。=
就我自己而言,float的第一、三个作用还是很好的,因为代码干净,通常也不会有副作用和bug。可是第二种用法就值得商榷了,因为它迫使设计师必须得清除浮动。这就说明浮动不只影响了自身,还影响了周围的元素。
看到这里你会想到什么?我觉得这就和程序中本该使用内部变量,却使用了全局变量,结果造成错乱,而不得不进行修复一样。
那么浮动的这种影响的成因是什么呢?
先来说说文档的布局吧。正常情况下,文档流是一行一行向下排列的,这每一行就是一个line box,而行内部的inline元素则是inline box:
<p>这一行是一个line box,<span>这个span是一个inline box</span>,这个没有被inline元素包围的则是匿名inline box。</p>
当我们把浏览器窗口缩小后,这个p元素可能就换行了,变成了多个line boxes,可是文字仍然是正常显示的,甚至将p的height设为0,这些文字仍然能显示。这就说明了inline box在显示时是无视height样式的,可浏览器要怎么决定它的高度呢?其实它用到了line-height这个样式。
所有的inline元素实际上都是无视height的,它们的高度由line-height决定(而line-height通常会设为与font-size相关的值)。其中有个例外就是多媒体元素:img、object、video和canvas等元素本身就有height属性,也可以被height样式控制,但是却不受line-height影响。
而一个line box为了包裹内部的所有inline boxes,就会自动将它的line-height设为这些inline boxes中最大的行高。
那么这与浮动有什么关系呢?
这里我和张鑫旭的看法有出入。他说浮动主要有2个效果:包裹和破坏。其中破坏是指破坏这个元素的的inline box,而破坏的结果就是浮动元素脱离了所在的line box。
实际上按照W3C CSS2.1标准的描述,float元素是脱离了文档流的,而不仅仅是脱离line box。但是后续的line box并不会与float元素重叠,而是乖乖地让开并围绕在其周围了。
至于float元素本身,实际上它的高度和行高都在,inline box也在,这点可以用这段代码来验证:
<p style="float:left"/>这是一个inline box<br/>这也是一个inline box</p>
可以看到这2行并不会重叠,说明行高是存在的。而且用Chrome和Firebug来审查元素,都会发现它们有height和line-height。因此行高和浮动并无直接联系,只是影响line boxes的高度而已。而正是由于有高度和宽度,浮动元素才能撑开周围的元素,让元素环绕在周围,而非覆盖。
实际上这个高度和宽度正是张鑫旭所说的包裹:浮动元素会正好包住内部的所有元素,不让它的宽度像block元素一样自动充满父元素。
所以在我看来,浮动应该是包裹和脱离文档流的组合。
考虑一个用float来实现横向导航栏的例子:每个li都是浮动元素,因此就尽量缩短自身的width,而由于有脱离文档流的特性,后续的元素会占据其后的位置,而非换行。
这里就暴露出一个问题:第一个li元素影响自己和其后的1个li元素;后续li元素只影响其后的1个li元素(影响自身的效果重叠了);而最后一个li元素实际上影响到了列表以外的1个元素。
所以正常而言,最后一个li元素不应该是浮动元素,因为它不需要影响后续元素。可是要实现这个效果,编程是比较麻烦的,CSS 3的:last-child也不被广泛支持。
于是为了减少麻烦,不得以而在后续元素上应用了clear样式,保证其不会被之前的float效果影响。
不过实际上脱离文档流并不是导航栏所需要的,它只要能横向排列即可。因此很正常就会想到inline元素,它默认就是横向排列的。
可是将li元素设为inline也不行,因为还有可能包含block元素(例如多级菜单)。那么正常而言,你应该能想到inline-block。这个玩意本身是个inline元素,因此会包裹并横向排列;同时内部是block元素,因此可以包含block元素。更关键的是:它没有环绕效果,只会影响自己,因此后续元素如果不是inline或inline-block的话,就会自动换行,不需要清除浮动。
于是看下面这个例子:
<style type="text/css">
.float-left{float:left}
.float-right{float:right}
.align-right{text-align:right}
.clear{clear:both;}
.inline-block {display:inline-block}
body>div {padding: 10px 0}
</style>
<div><div class="float-left">float-left元素</div> <div class="float-left">float-left元素</div> <div>block元素</div></div>
<div><div class="float-left">float-left元素</div> <div class="float-left">float-left元素</div> <div class="clear">clear元素</div></div>
<div><div class="inline-block">inline-block元素</div> <div class="inline-block">inline-block元素</div> <div>block元素</div></div>
<hr/>
<div><div class="float-left">float-left元素</div> <div class="float-right">float-right元素</div> <div>block元素</div></div>
<div><div class="float-left">float-left元素</div> <div class="float-right">float-right元素</div> <div class="clear">clear元素</div></div>
<div><div class="float-left">float-left元素</div> <div class="align-right">align-right元素</div> <div>block元素</div></div>
<div><div class="inline-block">inline-block元素</div> <div class="float-right">float-right元素</div> <div>block元素</div></div>
第一行没有清除浮动,因此block元素直接和float-left元素并排了。第二行清除了浮动,不足之处就是这个元素可能没有内容,只是个空元素而已。(虽然也可用CSS的content属性来生成,但毕竟也显得不干净。)
第三行用了inline-block,直接就很正常地展示出来了。不过每个div之间有个空格,可以利用letter-spacing和font-size来清除。
第四行同时使用了左右浮动,没有清除浮动,因此block元素直接插到中间去了。
第五行清除了左右浮动,可以正常显示了。
第六行用text-align来实现右对齐,由于它没有浮动,并且占据了剩下的空间,因此block元素可以正常显示。
第七行仍然是inline-block,为了节省时间,使用浮动来右对齐。由于inline-block和非浮动的block元素不能同处一个line box,因此也自动换行了。
另外,使用inline-block是不需要限制高度的,因为它没有脱离文档流,line box会自动计算行高来包裹inline boxes,不会出现float时元素高度不一致,自动就被高的元素挤开的情况。
0条评论 你不来一发么↓