3.2 盒子有多大

无论是对初学者,还是对专家来说,W3C盒模型的原理都是CSS最难理解的地方。在接下来的讨论中,我们将分别介绍块级元素(比如标题、段落和列表)和行内元素的不同行为。

为此,我们得一步一步地回顾盒模型。首先,谈一谈设定盒子的宽度,因为控制元素的宽度是创建多栏布局的头等大事。一开始我们会看到给没有宽度的元素添加边框、内边距和外边距的效果,然后再看看通过CSS给它设置了宽度之后,它的行为有什么不一样。

1. 没有宽度的盒子

所谓“没有宽度”就是指没有显式地设置元素的width属性,这是我专门为你造的一个词——等等,求你了,真不用谢我。另外,“元素”和“盒子”从现在起代表同一个意思,至于选择哪一个,就要看到时候两者哪个最直接明了。

如果不设置块级元素的width属性,那么这个属性的默认值是auto,结果会让元素的宽度扩展到与父元素同宽。下面我们来看一个宽度处于auto状态的元素。就使用下面这么简单的标记吧:

随着HTML5时代的到来,以及旧版浏览器退出历史舞台,用于确保站点在严格模式(使用W3C标准的盒模型)或混杂模式(适应IE6及更早版本的盒模型)下呈现的XHTML文档声明也就不再需要了。要了解什么是混杂模式,请参考这篇文章:http://www.quirksmode.org/css/quirksmode.html

  1. <body>
  2. <p>This element's width property is not set…</p>
  3. </body>

再配上以下CSS:

  1. body {font-family:helvetica, arial, sans-serif; font-size:1em; margin:0px; background-color:#caebff;}
  2. p {margin:0; background-color:#fff;}

在包含元素body上,我们设定了字体、背景颜色,删除了默认的外边距,这些设定在所有盒子宽度的盒子中将一直保持不变。而对于其中的段落,我们也删除了默认的外边距。删除了外边距后,body元素会填满浏览器窗口,而段落会填满body元素,如图3-8所示。

为了让大家看清每一步都发生了什么,我特地在窗口上方添加了一张标尺图片(代码没有给出)。这样,我也可以为了这个例子把浏览器窗口精确地缩小到400像素宽。

enter image description here图3-8 这个段落没有边框、内边距和外边距

在没有边框、内边距,也没有外边距的情况下,段落的文本扩展到了与body元素同宽。接下来用内边距给文本两侧添加一些空白,如图3-9所示。

  1. /*为简明起见,省略了字体声明 */
  2. p {margin:0; background-color:#fff; padding:0 20px;}

enter image description here图3-9 内边距使文本块变窄了

添加了内边距后,文本块的宽度变成了360像素(两边各加了20像素内边距)。

接下来,我们再给段落左右两边各添加6像素宽的边框,结果如图3-10所示。

  1. p {margin:0; background-color:#fff; padding:0 20px; border:solid red; border-width:0 6px 0 6px;}

enter image description here图3-10 添加边框会进一步减少内容区的宽度

为两边各添加6像素的边框和20像素的内边距后,内容区变成了348像素(400-52)。最后,再给左右两边各加一些外边距,结果如图3-11所示。

  1. p {margin:0 30px; background-color:#fff; padding:0 20px; border:solid red; border-width:0 6px 0 6px;}

enter image description here图3-11 加上边框、内边距和外边距后,内容区变得更窄了

外边距在元素盒子与窗口之间创造了空白,此时内容宽度变成了288像素(400 – ( (20 + 6 + 30)× 2) )。而元素声明的总宽度并没有变,仍然是400像素。

盒模型结论一:没有(就是没有设置width的)宽度的元素始终会扩展到填满其父元素的宽度为止。添加水平边框、内边距和外边距,会导致内容宽度减少,减少量等于水平边框、内边距和外边距的和。

2. 有宽度的盒子

好了,接下来我们再做一遍同样的练习,但这一次先用CSS声明元素的宽度,如图3-12所示。

  1. /*为简明起见,省略了字体声明*/
  2. p {width:400px; background-color:#fff; margin:0;}

enter image description here图3-12 明确设定width属性后,块级元素就不会再扩展到与父元素(即body)同宽了

这一次,段落有了固定的宽度400像素。在没有内边距的情况下,内容区也是声明的宽度,因此文本与盒子接触。下面给这个元素添加20像素的内边距:

  1. p {width:400px; background-color:#fff; margin:0; padding:0 20px;}

有了前一个例子的经验,你可能会认为这一次内容区宽度会缩小到360像素,可是你错了!在给盒子设定宽度后,添加内边距会导致元素比原来宽了40像素,如图3-13所示。

enter image description here图3-13 添加内边距使盒子变宽

要是再给盒子两边各添加6像素的边框呢,结果如图3-14所示。

  1. p {width:400px; background-color:#fff; margin:0;padding:0 20px; border:solid red; border-width:0 6px 0 6px;}

盒子比刚才又宽了12像素。现在,原来400像素宽的盒子变成了452像素(6 + 20 + 400 + 20 + 6 = 452)。

enter image description here图3-14 添加边框使盒子更宽了

最后,再给元素左、右两边添加一些外边距,如图3-15所示。

  1. p {width:400px; background-color:#fff; margin:0 30px; padding:0 20px; border:solid red; border-width:0 6px 0 6px;}

enter image description here图3-15 外边距在盒子周围添加了空白,为了展示盒子占据的空间,浏览器窗口也拉大了

添加的这30像素外边距,进一步增大了元素占据的空间,目前总宽度已达到512像素(30 + 6 + 20 + 400 + 20 + 6 + 30 = 512)。

盒模型结论二:为设定了宽度的盒子添加边框、内边距和外边距,会导致盒子扩展得更宽。实际上,盒子的width属性设定的只是盒子内容区的宽度,而非盒子要占据的水平宽度。

为什么我要这么不厌其烦地演示没有宽度的盒子和有宽度的盒子,在被添加了边框、内边距和外边距时所表现出来的不同行为呢?这两种盒子所表现出来的完全不同的行为,对将来构建多栏布局具有重要的启示。因为在多栏布局中,每一栏都必须时刻维护自己的宽度。第5章将会讨论的“浮动布局”,在列宽由于边框、内边距和外边距被修改而意外加宽的情况下,会出现显示错误。

总之,你要记住一点:设定了元素的width属性后,再给元素添加边框、内边距和外边距,元素的行为与默认的auto状态下会有截然不同的表现。

CSS3新增了一个box-sizing属性,通过它可以将有宽度的盒子也设定成具有默认的auto状态下的行为。但只有最新版本的浏览器才支持该属性,所以在本书写作时(2012年夏天),我还不能推荐你使用它。

下一节我们聊一聊浮动和清除,它们可是在创建CSS布局之前都必须理解的关键技术。