什么是浮动?
CSS中的一些元素是块级元素,表示它们会自动另起一行。
举个例子,如果你创建了两个段落,每个段落都只有一个单词。这两个单词不会靠在一起,而是会各自占据一行。
另一些元素是行内元素,表示它们和前面的内容位于相同的一行。
举个例子,<a>可以出现在另一个元素中,比如<p>,这不会产生多余的空格或者出现换行。
欺骗这种布局模型的一种方式是使用浮动,浮动可以让一个元素移到它所在行的某一边,使得其他内容沿着该元素的边缘向下流。
一个典型的例子是你想要一张图片和一个段落并排出现,而不是一上一下排列。首先我们先来创建HTML:
1 2 |
|
单独这段代码并不能实现我们想要的效果。<p>是一个块级元素,它会独占一行,所以图片和段落是一上一下展现的。
通过让图片向右浮动可以改变这种行为,如下:
1 2 3 4 |
|
这样,图片就跑到右边去了,而段落则沿着图片的左边向下流式布局。
现在发生了一件有趣的事,当这张图片浮动后,其他的内容就会想办法尽可能的包围它。如果我们resize容器或者浏览器窗口,让它更窄,这段文本就会发生重排(reflow),这样它就永远不可能接触到图片。
盒模型如何工作
也许你已经对上面所讲的知识有了深刻的理解。但是,为了完全掌握浮动,你需要更加深刻的理解两个元素如何互相作用。举个例子,如果我们在段落和图片之间加一个边距会发生什么?
p {margin: 20px;}
但是呢,这么写并不会在图片和段落之间产生额外的空间。实际上,我们需要给图片加margin:
img {margin: 20px;}
也许你会问为什么呢?为什么增加<p>的margin不会增加图片和段落的间距呢?
原因是我们没有理解<p>的盒模型。
如果现在你对布局产生了一些疑虑,可以试着加一个或者两个border,看看会发生什么。下面给<p>加border:
p { border: solid 1px black; }
如你所见,图片实际上位于<p>盒模型的内部!这就可以解释刚才的margin问题。我们加到<p>上的margin其实是作用于图片的右侧,这就是为什么它不能增加图片和段落之间的距离!
如果我们想改变这种行为,使得段落不会包围图片,我们应该让段落向左浮动,并设置一个宽度(如果不设置,<p>的宽度默认是100%,这样就不会和图片紧挨着了,因为如果段落很长,它会跑到下一行)。
img { float: right; margin: 20px; } p { float: left; width: 220px; margin: 20px; }
疯狂的浮动规则
现在你知道什么是浮动了,并且知道浮动如何影响相关元素的盒模型。接下来要说的也许很多人都不了解:如何调整浮动元素的位置。
web开发中很多人会给<li>使用浮动。下面来看一个例子:
<ul> <li><img src=""/>1</li> <li><img src=""/>2</li> <li><img src=""/>3</li> <li><img src=""/>4</li> <li><img src=""/>5</li> <li><img src=""/>6</li> <li><img src=""/>7</li> </ul>
所有<li>默认应该是垂直方向上排列的,这就表示<li>是块级元素。即使图片是行内元素,它也会被它的父级块级元素管理。为了解决这个问题,我们让<li>向左浮动。当一行内的多个<li>被浮动后,它们会产生类似行内元素的流式布局。然而,正如你即将看到的,它们有一些关键的不同。
li { float: left; margin: 4px; }
现在,如果所有图片的高度相同,就会产生下面的效果。
但是,我们的图片高度不是一样的,一些是100px,另一些是150px。这就引起了一些严重的问题!
当我第一次看到这个效果,我蛋疼了。为什么图片4跑到右边去了?它不是应该尽可能的向左浮动么?如果我们放弃浮动而使用display:inline,结果会大不一样。
li { display: inline; }
这个例子中,图片默认是垂直居底(bottom)对齐。这和我们之前的例子不同,为了解决对齐问题,我们添加一行CSS。
img { vertical-align: top; }
由此可知,使用display:inline 可以更容易猜到<li>的排列结果。当水平方向没有多余的空间时,下个元素就会另起一行。
浮动为什么不能实现这种效果呢?
CSS规范对于浮动行为概括了9个规则。但问题是,只有规范的作者和那些无聊的人才能理解这些规则。下面摘录了其中一个规则:
“If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.”
对于这些规则,也许你比我理解的更深,但说实话,这些规则让我非常蛋疼。为了简化它,Josh Johnson给出了他的9条规则(注:我觉得这位仁兄的9条规则依然很啰嗦,我再给精简一下):
1. 浮动元素的活动区域
仅限于它的父容器元素,不会超出父容器
2. 浮动元素的位置
水平方向:尽可能居左或居右,如果它前面还有浮动元素,会跟在它后面,如果超出该行就会换行
垂直方向:尽可能的居顶
关于水平方向的位置,需要注意以下几点:
1) 向左浮动的元素不会出现在向右浮动的元素的右侧
关于垂直方向的位置,需要注意以下几点:
1) 浮动元素不会比容器的顶部还高
2) 浮动元素不会比前一个块级元素或浮动元素更高
3) 浮动元素不会比前一个行内元素更高
在布局时,垂直方向的规则比水平方向的优先级更高
总的来说就是,浮动元素会移到左侧或右侧。除非该元素前面还有一个浮动元素,这时它就会紧挨着前面的元素。
真正让人迷惑的是:浮动元素会尽可能的居顶,并且垂直定位规则比水平浮动规则的优先级更高。
在前面的例子中,图片2撑高了该行的高度,所以在放完图片3后,仍然有足够的垂直空间放置图片4。
记住,当你有一个浮动元素(不位于尾行)时,它后面的浮动元素占用的垂直空间必须大于或等于它才会触发换行。
浮动顺序
举个例子,我们有6张图片的一个列表。
<ul> <li><img src="http://placehold.it/100x100&text=1"/></li> <li><img src="http://placehold.it/100x100&text=2"/></li> <li><img src="http://placehold.it/100x100&text=3"/></li> <li><img src="http://placehold.it/100x100&text=4"/></li> <li><img src="http://placehold.it/100x100&text=5"/></li> <li><img src="http://placehold.it/100x100&text=6"/></li> </ul>
如果我们向左浮动图片,它们就会按照原来的顺序排列。但如果向右浮动呢?
可以发现,第一张图片占据了最右的位置。类似的,换行后,第四张图也占据了最右的位置。这就是为什么你很少看到导航栏的列表项会向右浮动的原因。
清除浮动
使用浮动可以方便的实现一些布局,比如创建n栏内容。但是呢,一旦使用浮动就会影响文档正常的流式布局。比如,刚才那个例子中,我们想在列表下方加上一个段落。
这个结果也许不是你想要的。这里的解决方法是使用 clear 属性,它的作用是清除该元素某侧的浮动。比如,我们对第二个列表项使用clear:left
ul li:nth-child(2) { clear: left; }
这段代码告诉浏览器第二项的顶部必须比它前面的浮动元素的底部更低。如果所有列表项是向右浮动的,则需要使用clear: right
加上段落文本再看
很明显这依然不是我们想要的效果,解决方法是给段落使用clear,这会使得段落出现在浮动元素的下方而不是与它们相邻。
p { clear: both; }
其实这里我们只需要清除左侧的浮动即可,但是当一个开发者为了确保清除了所有浮动,clear:both是很常用的一种方法。
浮动的问题和clearfix
当一个元素只包含浮动元素时,该容器元素会出现高度重叠(和高度为0的效果一样,即高度的顶边和底边重叠)。为了演示这个现象,我们还是使用刚才的例子,只是给列表加一个背景色。
ul { background: gray; }
如果列表项没有浮动,可以看到整个列表都是灰色的,而列表项则是从上到下排列。
现在我们浮动所有列表项,这时<ul>只包含浮动的元素,所以它的高度重叠了,新手肯定会好奇背景色到底哪去了.
解决这个问题有好几种方法,最简单的一种是直接给容器元素设置高度。
ul { height: 300px; }
这样背景色又回来了。但是,这种方法常常不能让我们满意,因为当我们需要容器的高度和内容自适应时,这种方法完全无效。如果我们再加上三个列表项,这个高度又不够了。
召唤clearfix
现在该轮到clearfix登场了,它通过clear属性解决了高度重叠的问题。
我们常常会创建一个空元素(通常是div),它和浮动元素同级,然后给它设置class为“clearfix”。回到CSS,我们加上这样一行样式:
.clearfix { clear: both; }
这样就解决了高度的问题。
说下原理:我们知道当元素只包含浮动元素时,高度发生重叠(效果和高度为0一样),这时该元素有了一个子元素,即使它是个空元素,但它没有浮动,而且还清除了所有浮动,所以这个空元素会出现在所有元素的下方,从而撑起了容器的高度,于是height:auto恢复正常了。
这种方法的缺点是,HTML中多了一个额外的元素,不符合语义化的思想。
新的解决方法是使用 overflow 属性,如果你设值为hidden 或 auto,也可以解决高度重叠的问题。
ul { overflow: auto; }
这种方法更简单也更优雅,但是还有个问题要说下,如果容器元素必须设置为overflow: visible,你又该怎么办呢?
方法是首先使用 :before 和 :after 在元素内创建一些不浮动的东西,但实际上你并不希望出现任何多余的东西,所以我们设置一个空字符串,但是要设置display:table,这样就创建了一个匿名单元格(是不是想起了<td></td>?),最后使用老办法,清除浮动。
为了兼容老版本的IE,使用它特有的zoom:1清除浮动。
/* For modern browsers */ .cf:before, .cf:after { content:""; display:table; } .cf:after { clear:both; } /* For IE 6/7 (trigger hasLayout) */ .cf { zoom:1; }