3.1 理解盒模型
早在第1章我们就讲过了,每一个元素都会在页面上生成一个盒子。因此,HTML页面实际上就是由一堆盒子组成的。
默认情况下,每个盒子的边框不可见,背景也是透明的,所以我们不能直接看到页面中盒子的结构。同样,我们也介绍过,使用Web Developer工具条,可以方便地显示出盒子的边框和背景,从而让我们能从另外一个角度来审视页面的构成。
好啦,我们先从每个元素盒子的属性开始吧。这些属性可以分成三组。
- 边框(border)。可以设置边框的宽窄、样式和颜色。
- 内边距(padding)。可以设置盒子内容区与边框的间距。
- 外边距(margin)。可以设置盒子与相邻元素的间距。
怎么理解这几组属性呢?最简单方法是想象一下外边距是边框向外推其他元素,而内边距是从边框向内推元素的内容,参见图3-1。一个盒子有4条边,因此与边框、内边距和外边距相关的属性也各有4个,分别是上(top)、右(right)、下(bottom)、左(left)。
要了解有关盒模型的更多信息,请参考这里:http://www.w3.org/TR/REC-CSS2/box.html。
图3-1 这个盒模型示意图展示了HTML元素的边框、内边距和外边距之间的关系
图中文字:Border:边框;Padding:内边距;Margin:外边距
元素盒子还有一个背景层,可以改变颜色,也可以添加图片。与元素背景相关的属性将在本章后面介绍。
虽然可以用总共12个属性分别为4条边的边框、外边距和内边距指定宽度,但CSS也为我们提供了简写属性。详细信息请参考附注“简写样式”。
简写样式
CSS为边框、内边距和外边距分别规定了简写属性,让你通过一条声明就可以完成设定。在每个简写声明中,属性值的顺序都是上、右、下、左。想象一下顺时针旋转就记住了。举个例子吧,如果要设定盒子的外边距,不用简写属性就得这样写:
{margin-top:5px; margin-right:10px; margin-bottom:12px; margin-left:8px;}
而使用简写属性,则可以简写为这样:
{margin:5px 10px 12px 8px;}
注意,4个值之间有空格,但不能是其他分隔符(比如逗号之类的)。甚至,你都不用把4值全都写出来——如果哪个值没有写,那就使用对边的值。
{margin:12px 10px 6px;}
对这个例子来说,由于没有写最后一个值(左边的值),所以左边就会使用右边的值,即10px。而在下面的例子中:
{margin:12px 10px;}
只写了两个值,上和右,因此缺少的下和左就会被设定为
12px
和10px
。最后,如果你只写一个值:
{margin:12px;}
那么4个边都取这个值。使用这种简写属性,不能绕开上和右,只给下和左设定值,即使上和右都是零也不行。绕不开怎么办?如果它们真是零的话,那就写
0
呗,比如:
{margin:0 0 2px 4px;}
另外,每个盒子的属性也分三种粒度,到底选择哪个粒度的属性,要看你想选择哪条边,以及那条边的哪个属性。这三种粒度从一般到特殊分别是举例如下。
- 全部3个属性,全部4条边
{border:2px dashed red;}
- 1个属性,全部4条边
{border-style:dashed;}
- 1个属性,1条边
{border-left-style:dashed;}
混合使用这三种粒度的简写属性达成设计目标是很常见的。比如说吧,我想为盒子的上边和下边添加4像素宽的红色边框,为左边添加1像素宽的红色边框,而右边没有边框。可以这样写:
- {border:4px solid red;} / 先给4条边设置相同的样式 /
{border-left-width:1px;} / 修改左边框宽度 /
{border-right:none;} / 移除右边框 /类似地,其他属性也都有这三级粒度,例如
padding
和border-radius
等。
3.1.1 盒子边框
边框(border
)有3个相关属性。
- 宽度(
border-width
)。可以使用thin
、medium
和thick
等文本值,也可以使用除百分比和负值之外的任何绝对值。 - 样式(
border-style
)。有none
、hidden
、dotted
、dashed
、solid
、double
、groove
、ridge
、inset
和outset
等文本值。 - 颜色(
border-color
)。可以使用任意颜色值,包括RGB、HSL、十六进制颜色值和颜色关键字。
CSS推荐标准并未明确规定
border-width
这几个文本值thin
、medium
和thick
的确切宽度,实际显示的宽度可能会因浏览器而异。对于边框样式(border-style
),除了solid
值(实线)之外,CSS规范也没有明确规定。因此dashed
值(虚线)在不同浏览器中的短划线长度和线间距也可能会不一样。
border
的第四个属性border-radius
并不影响盒模型的定位,所以我们放在第7章再介绍。
前面附注栏“简写样式”里已经展示了几个边框相关的样式了,但下面我们要举几个稍微复杂点的例子,以进一步巩固你的理解。
p.warning {border:solid #F33;}
有了这条规则,任何带有warning
类的段落都会带上一个吸引眼球的、4像素宽的红色实心边框,如图3-2所示。
图3-2 在这里,我希望4条边样式相同,因此就使用了border
简写属性
假如我为了让边框看起来更有意思,想在4条边都是红色实心边框的基础上,把右边框和下边框变窄一些,那么可以在前面规则基础上新写一条规则。前面那条规则使用了“所有4边一次性”设定的便捷属性 border
,为4条边设定了基础。下面这条新规则可以使用border-width
修改个别边框的宽度:
p.warning {border:solid #f33;}
p.warning {border-width:4px 1px 1px 4px;}
结果如图3-3所示。
图3-3 使用border-width
属性,可以为盒子的每条边单独设定宽度
在实际开发的时候,为了看清楚margin
和padding
的实际效果,可以临时设定盒子的边框。默认情况下,边框的三个相关属性的值分别为border-width:medium;
、border-style:none;
、border-color:black;
。由于border-style
的默认值是none
,所以不会显示盒子的边框。为了快速地把盒子边框显示出来,可以这样写一条规则:
p {border:solid 1px;}
这样就把border-style
设定为实线(solid
),于是边框就出现了。当然,这里也把边框宽度由默认的3像素变窄为1像素,从而把边框对布局宽度和高度的影响降到最低。
3.1.2 盒子内边距
内边距是盒子内容区与盒子边框之间的距离。图3-4展示了一个带边框的元素的内容区,应用给该元素的规则如下。
p {font:16px helvetica, arial, sans-serif; width:220px; border:2px solid red; background-color:#caebff;}
图3-4 在没有设定内边距的情况下,内容紧挨着边框
如果你什么也不做,那么元素的文本就会像这样紧挨着元素的边框,这看着可让人有点不舒服。其实,只要给元素添加一点内边距,情况就会大为改观,如图3-5所示,规则如下。
p {font:16px helvetica, arial, sans-serif; width:220px;border:2px solid red; background-color:#caebff; padding:10px;}
图3-5 只要显示元素边框,为防止文本挨上它就得添加内边距
由于内边距在盒子的内部,所以它也会取得盒子的背景。仔细比较一下图3-4和图3-5就会发现,内边距实际加在了声明的盒子宽度之上。换句话说,多出来的内边距并没有像我们想象的那样挤压文本内容,这是怎么回事儿了呢?请容我先在这里卖个关子,本章后面再给大家解释。
3.1.3 盒子外边距
与边框和内边距相比,盒子的外边距要复杂一些。在图3-6中,有三组标题和段落。第一组标题和两个段落使用默认样式。第二组与第一组唯一的区别就是多了边框,但因此也可以看清标题与段落间的外边距有多大。第三组展示了把外边距设置为零之后的效果,该组的标题和段落全都紧挨在一起了。
图3-6 学会控制元素周围的外边距是布局的重要技能
中和外边距和内边距
推荐大家把下面这条规则作为样式表的第一条规则:
* {margin:0; padding:0;}
这条规则把所有元素默认的外边距和内边距都设定为零。把这条规则放到样式表里后,所有默认的外边距和内边距都会消失。然后,你可以为那些真正需要外边距的元素再添加外边距。稍后我们会介绍,不同浏览器默认的内边距和外边距也不一样,特别是对表单和列表等复合元素。在这种情况下,用前面那条规则“中和”默认值,然后再根据需要添加,则会在各浏览器上获得一致的效果。
我在自己的项目中使用了Eric Meyer写的重置样式表reset.css。这个样式表不仅重置了外边距和内边距,还对很多元素在跨浏览器显示时的外观进行了标准化。 至于Eric为什么要写一个涉及面如此之广的重置样式表,可以参考他的文章http://meyerweb.com/eric/thoughts/2007/04/18/reset-reasoning,reset.css的下载地址是http://meyerweb.com/eric/tools/css/reset。
3.1.4 叠加外边距
垂直方向上的外边距会叠加,这可是你必须得知道的一件事。本节就来解释一下什么叫外边距叠加,为什么它那么重要。假设有3个段落,前后相接,而且都应用以下规则:
/*为简明起见,省略了字体声明*/
p {height:50px; border:1px solid #000; backgroundcolor:#fff; margin-top:50px; margin-bottom:30px;}
由于第一段的下外边距与第二段的上外边距相邻,你自然会认为它们之间的外边距是80像素(50+30),但是你错啦!它们实际的间距是50像素。像这样上下外边距相遇时,它们就会相互重叠,直至一个外边距碰到另一个元素的边框。就上面的例子而言,第二段较宽的上外边距会碰到第一段的边框。也就是说,较宽的外边距决定两个元素最终离多远,没错——50像素(参见图3-7)。这个过程就叫外边距叠加。
图3-7 垂直外边距叠加(或者叫重叠),直到一个元素的外边距碰到另一个元素的边框为止
注意啦,叠加的只是垂直外边距,水平外边距不叠加。对于水平相邻的元素,它们的水平间距是相邻外边距之和。这跟你最初想的一样。
好吧,我想必须得解释一下为什么要让外边距叠加。如果有一连串段落都被应用了相同的样式,那么对其中第一段和最后一段来说,它们的上外边距和下外边距决定了它们与包含元素的间距。而那些位于中间的段落呢,根本不需要两个外边距加起来那么宽的间距。因此,就像图3-7所示的那样,相邻的外边距叠加起来是最合理的,哪个外边距宽,就以哪个外边距作为段间距。
3.1.5 外边距的单位
根据经验,为文本元素设置外边距时通常需要混合使用不同的单位。比如说,一个段落的左、右外边距可以使用像素,以便该段文本始终与包含元素边界保持固定间距,不受字号变大或变小的影响。而对于上、下外边距,以em为单位则可以让段间距随字号变化而相应增大或缩小,比如:
/*这里使用了简写属性把上、下外边距设置为.75em,把左、右外边距设置为30像素*/
p {font-size:1em; margin:.75em 30px;}
这样,段落的垂直间距始终会保持为字体高度的四分之三(上下外边距都是.75em
,叠加后还是.75em
)。如果用户增大了字号,那么不仅段落中的文本会变大,段间距也会成比例变大。这样,页面的整体布局就会比较协调一致。与此同时,使用像素单位的左、右外边距不会改变。我想,你应该也不会想让字号变化影响到布局宽度吧。