本教程出自于白师傅、本节包含 2 个内容: 浮动 ( Float ) 和 盒模型 ( Box Model ).

Float

HTML标签中,有一些标签称为块标签(Block, 如:<p><div>),对于这样的标签,如果我们不说明其宽度,它将占满它可以使用的所有横向(水平)空间。即使设置了宽度,它也不会与同属一个父容器其它元素同处一行。

而有一些标签称为行内标签(Inline, 如:<span><img>),这样的标签默认会与同属一个父容器的其它元素同处一行。

: O 有点晕!看下面的例子:

例2.1

1
2
3
4
5
<p style="border:1px solid red;">段落一</p>
<p style="border:1px solid green;">段落二</p>
<p style="border:1px solid blue; width:200px;">段落三</p>
<span style="border:1px solid red;">Span1</span>
<span style="border:1px solid green;">Span2</span>

浏览器中显示效果如下图:(外层淡蓝色为浏览器的边框,即本例中 <p><span>的父容器边框)

现在明白了吧……

细心的读者可能会有疑问,不是说块标签会占满横向空间嘛,怎么3个段落两端和浏览器边框之间还有一段间隙呢?

这是由于默认情况下,<body> 标签会有一点留白,你可以在 <body> 标签中添加样式,如 <body style="margin:0px;>,试试看,是不是没有间隙了?

块标签或行内标签只是针对标签的默认情形而言,我们可以使用样式 display:inline<p> 标签显示为行内标签的样子,同样也可以使用样式 display: block<span> 标签显示为块标签的样子。

OK,讲到这里可能有人会记下这样一句话:如果要让元素们同处一行,就把它们的 display 样式属性设置为inline

可别这样,我们还有更好的办法,上面只是为了插叙一下块标签和行内标签的概念。

把上面例子中的代码修改一下,在每个 <p> 标签的样式中都插入 float: left :

1
2
3
<p style="border:1px solid red;float:left;">段落一</p>
<p style="border:1px solid green;float:left;">段落二</p>
<p style="border:1px solid blue; width:200px;float:left;">段落三</p>

结果变成这样了:

让我们欢迎这一节的主角 float 登场!

正如你看到的,样式属性 float 可以让元素产生”浮动”效果,上面的例子让3个段落都向左浮动,于是它们就一个挨个地”飘”到一起了。当然,也可以设置为向右浮动或不浮动。

使用 float 时有几个问题需要注意:

(1) 当一个容器中的多个元素 float 时,它们会努力地”飘”到同一行上,但如果容器横向空间不够,余下的元素就会向下”飘”, 请比较例 2.2 和 2.3。

例 2.2

<div style=”border:2px solid red; width:300px; height:100px;”>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#69F; width:100px; height:50px; float:left;”></div>
</div>

运行效果如下:

例 2.3

<div style=”border:2px solid red; width:300px; height:100px;”>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#69F; width:101px; height:50px; float:left;”></div>
</div>

运行效果如下:

例2.2 中外层DIV限定了宽度为300px,里面的3个DIV若宽度均是100px,总共宽度是100px * 3 = 300px,刚好可以放在同一行上。但若蓝色DIV稍宽1px,就被”挤”下来了(例2.3)。

好的,现在在例2.2的基础上,为里面的蓝色DIV设置1px宽的边框,如 border:1px solid blue;,在浏览器里打开试试看,什么情况? 蓝色的 DIV 是不是同样放不下, 掉下来了.

(2) 当一个容器中的元素 float 时,会使得父容器在垂直方向”坍缩”。

例 2.4

<div style=”border:2px solid red;”>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;“></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;“></div>
<div style=”background-color:#69F; width:100px; height:50px; float:left;“></div>
</div>

运行效果如下:

什么情况? 怎么外层的DIV变成一条线了? 是的,现在看到的一条水平红线其实是外层DIV上、下两条红色边框紧挨在一起形成的,换句话说,外层的DIV没有计算得到正确的高度 ( 父容器在垂直方向上”坍缩”了 )。

为什么会这样?

外层DIV的高度其实是由其内部的 3 个DIV”撑”起来的。现在内部的3个DIV都向左浮动(float:left)了,都”飘”起来了,不再与外层DIV在一个水平面上了,自然也就无法把外层DIV撑开了。

呵呵,有意思吧,float属性真的可以让元素浮起来! 看看下图,可能更好理解(它们其实是这样)。

OK,现在问题来了,通常情况下,我们希望容器可以随其内容长大,始终套住其子元素。怎么办呢? 有3种较常用的做法:

方法 1: 让外层DIV也浮起来,代码如下:

<div style=”border:2px solid red; float:left;“>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#69F; width:100px; height:50px; float:left;”></div>
</div>

现在所有DIV都在”第二层空间”上了,外层DIV又可以正常计算得到高度值了。但这样会让外层DIV的宽度变成300px,而不是占满所有可用横向空间(也许,这正是你想要的效果,那你就这样用)。

方法 2: 给外层DIV添加样式 overflow: hidden,代码如下:

<div style=”border:2px solid red; overflow:hidden;“>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#69F; width:100px; height:50px; float:left;”></div>
</div>

诡异吧,不是说内容溢出( overflow )时隐藏 ( hidden ) 吗? 怎么非但没隐藏内层的3个DIV,却把自己父容器变高了?

我想可以姑且这样理解,样式 overflow:hidden 要求父容器在装不下子元素时隐藏溢出的部分, 这会让浏览器认真考量一下父元素到底应该有多高, 正是这个动作使得父容器计算得到了正确的高度。

方法 3: 使用”空层”清除浮动:

<div style=”border:2px solid red;”>
<div style=”background-color:#CF6; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#FC3; width:100px; height:50px; float:left;”></div>
<div style=”background-color:#69F; width:100px; height:50px; float:left;”></div>

<div style=”clear:both;”></div>

</div>

方法三中我们插入了上面红色的这行代码,添加了一个看不见的层(未设置大小),并且设置样式 clear:both (清除左、右两个方向上的浮动)。

姑且可以这样理解,新插入的层在前3个DIV均在”第二层空间”摆好了位置之后清除了浮动,让它们又落回了”第一层空间”.

上述3个方法中,方法1让所有元素都浮起来了,个人认为不太好,本人更偏好后两种做法。

盒模型

经过前面的学习,我们知道,从一个元素的内容区往外走,首先会踫到padding,然后是border,最后是margin,这3个东东就像是3层盒子套住了内容区,我们把它称为盒模型 (Box Model)

看下面2个图,可能对你的理解有帮助。

仔细研究你可能会发现第一个图中红线标注的部分在说CSS标准中与IE对样式width的理解不一样,但这其实是历史问题, 经本人在IE 9.0下验证,不存在这个问题, 即 IE 9.0 理解的width也是指内容区(Content)宽度.

还愣着干什么,快实验一下吧…

OK, 继续…

比较下面例3.1和3.2的结果, 例3.1中设置了外层DIV的宽、高,但未设置内层DIV的宽度;例3.2中只设置内层DIV的宽、高,未设置外层DIV的大小。

别愣着, 把代码复制到 HMTL 文档里, 在浏览器里打开看一下! 你将发现种在以下两种情况下,内、外层DIV是如果计算大小的。( 如果领悟到了什么就记下来吧! )

例3.1

<body style=”margin:0px;”>

  <div style=”border:10px solid #000; margin:10px; padding:10px; background-color:#CF3;

height:50px; width:50px;“>

    <div style=”background-color:#FFF; height:50px;”>>/div>

  </div>

</body>

例3.2

<body style=”margin:0px;”>

  <div style=”border:10px solid #000; margin:10px; padding:10px; background-color:#CF3; float:left;>

    <div style=”background-color:#FFF; width: 50px; height:50px; “></div>

  </div>

</body>

通过前面的讲述和实验,我们发现:

a) 一个元素实际占据的横向空间宽度 = 内容区宽度 width + padding + border + margin,纵向高度类似。(对于块标签特指float时)

b) 若为元素设置一个大于 0 的margin-left值,元素会连同边框一起向右偏移,而设置一个大于 0 的padding-left值,元素内容区会相对左边框向右偏移。同样,设置大于 0 的margin-toppadding-top可令元素向下偏移。

充分利用此特性,可进行元素定位(页面布局),这也是传说中的DIV+CSS 网页布局的重要基础。关于DIV+CSS 布局方法,请参阅CSS入门精要第(四)部分 综合示例.

c) marginpadding可以设置为负值(小于 0 的值),此时元素将向左/上偏移. 有时设置为负值可有意外惊喜~

对于margin还有一个特别的地方,我们再多说几句……

看下面的例子:

例3.3

1
2
<div style="background-color:#6CF; width:50px; height:50px; margin-right:10px;float:left;"></div>
<div style="background-color:#FC0; width:50px; height:50px; margin-left:20px;float:left;"></div>

例3.4

1
2
<div style="background-color:#6CF; width:50px; height:50px; margin-bottom:10px;"></div>
<div style="background-color:#FC0; width:50px; height:50px; margin-top:20px; "></div>

运行结果如下, 左图为例 3.3 的结果, 右图为例 3.4 的结果:

呵呵,有意思吧!

水平放置时,相邻的两个DIV间距为30px,即左边DIV的margin-right(10px) + 右边DIV的margin-left(20px) (求和)

垂直放置时,相邻的两个DIV间距为20px,不再是margin求和,而是取较大值。即上面DIV的margin-bottom和下面DIV的margin-top两个值中的较大值(20px)

这叫外边距合并(融合),虽然看上去增加了记忆的难度,但实际应用中这样的设计却更为合理,它可以使得纵排的多个元素之间的距离与元素与外层容器之间的距离保持一致。


好了, 本节到此结束, 在这一节里我们学习了浮动与盒模型的概念与用法, 在进入下一节之前, 建议回头再过一遍前面 (一)、(二)两节的内容.

最后留一个传送门, 传送到 CSS 入门精要(三) CSS 选择符