狠狠撸

狠狠撸Share a Scribd company logo
颁厂厂布局
        2010.06.29
十年磨一剑 Strict.dtd@gmail.com
本文档的内容分为两部分

  ? CSS盒模型
  ? 实例分解
什么是CSS盒模型?

CSS盒模型是颁厂厂布局的基础,是学习CSS需要了解的几个最重要的
概念之一。

它决定着一个元素在页面上的大小,也决定着margin、padding等等这些CSS属
性是怎么影响一个元素的。margin、padding这些都是我们平时很常用的CSS属
性,它们用起来也很简单,当为一个元素定义了margin、padding后会产生怎样
效果我们都想得到。

那为什么还要来了解CSS盒模式呢?会产生怎样的效果只一个表面现象,要用好
CSS知道这些表面的东西还不够,还需要知道为元素定义这些属性后为什么会产
生这样的效果;很多时候要实现某一个布局有多种方式,到底用哪种更合适;网
页大多都由很多元素组成,为这些元素定义大小、位置时它们之间是怎样相互影
响的。要回答这些问题并不难,但前提我们需要对CSS盒模式有足够的了解,在
理解了CSS盒模式、浮动、定位等等这些CSS的重要概念后,我们就能用更简洁
、高效的代码来实现各种布局效果。同时也有助于我们提升解决bug的能力,因
为这会让我们更多的了解bug背后的为什么,而不是遇到一个bug时就到处找资料
、找解决方法。
前面说过CSS盒模型决定着margin、padding等等这些属性怎么影响一
个元素,那么下面就用一个我们最常用div标签来理解CSS盒模型,了
解这些属性是怎么影响元素的。
看看下面这段代码

<div>CSS盒模型</div>

一个div开始标签和一个div结构标签包裹着一段文本,这在html中就称为一个div
元素,把这段代码加到一个html文件中,在我们没定义样式情况下浏览器会怎样
显示呢?
很简单,就一行文本,没有边框也没有背景,或者我们可以为它加一个
padding属性,像下面这样。

<div style="padding:30px;">CSS盒模型</div>

注:最好不要把CSS通过style属性直接添加元素上,因为这样做既没效率也不便
日后的维护,当然除非有特殊情况就特殊对待了。我在这里只是为了方便演示效
果才这么做的 ?

在添加了一个padding后再看看浏览器是怎么显示的。
我们能看到的其实还是一行文本,只是文本周围多了一些空白,但浏览
器并不是像我们这样来"看"这个元素的。

元素框(element box)

CSS假定每个元素都会生成一个矩形框,术语称之为“元素框(element box)”,
元素框的大小由4部分属性决定:width与height、padding、border和margin,前
面那个div元素在添加一些padding后,它的元素框的大小会是下面这样子。
或者我们可以再为它定义一些margin和border,像下面这样:
<div style="margin:30px;padding:30px;border:solid 30px blue;">CSS
盒模型</div>

在添加这些属性后元素框的大小又会有怎样的变化呢?




这是浏览器所显示的效果,当然这只是我们视觉上所看到的,这div元素的元素框
大小并不是这样子。
实际元素框的大小是这样




最里面的黄色区域就是核心内容区,这个区域的大小由width和height决定,紧挨
着内容区域的是padding、接着是border、然后是margin,这些属性值的总和就
是这个元素框的大小。

注:这些背景颜色是为了方便理解这个元素框而添加的,实际上元素框我们在视
觉上是看不到的。
看看下面这幅画




这幅画就能很好的来说明CSS元素框的形成,这个画框中间的画就是核心内容区,
这个框框可以理解为border,画离框框的距离就是padding,而这个画框与墙壁的
距离或者与相邻画框的距离就是margin,这些因素共同决定着这幅画在墙壁上所占
的空间。同样,这些因素也共同决定着一个元素在页面上所占的空间。
一个元素框在页面上所占的空间是怎么计算的呢?

先看下一个元素框高度的计算方式




元素框高度 = height + margin-top + margin-bottom + border-top + border-bottom
+ padding-top + padding-bottom

这7个属性值的总和就等于元素框的高度。如果margin、border、padding这些值为
0时,这个元素的高度就由height值来决定了,但页面上的元素大多没有定义一个固
定的height值的,那么这个时候元素框的高度就是由内容来决定的。就像我们前面
看到的那个div元素,在没定义样式时它的高度就由内容决定。
上面是浏览器所显示的效果,下面的黄色背景区域就是元素框的实际大小了
同样,元素框的宽度也是由7个属性决定




元素框宽度 = width + margin-left + margin-right + border-left + border-right +
padding-left + padding-right

这可以称之为水平方向的7属性,这7个属性值之和就是元素框的宽度。和元素框高
度一样,在margin、border、padding为0时,元素的宽度就由width值来决定,但
如果没有定义一个固定的width值,那这个时候决定元素框宽度的因素与决定高度的
因素就有一些区别了,它并不是由内容来决定,每个元素框的宽度都有一个相对的
范围,就是由它的父元素的width值来定义的。
看看下面这段代码

<div id="div1" style="width:400px;">
  <div id="div2">CSS盒模型</div>
</div>

div1的width值为400px,那么div2的元素框宽度就始终是400px,注意我说的是元
素框的宽度,也就是div2的水平方向7属性之和始终是400px。

这里大家可能会觉得困惑,只要把width、padding、margin等等这些值定义得较大,
那加在一起很容易就能超过400px,或者也可以定义得较小,加在一起就不到
400px,那这不是有和前面说的有冲突吗?

当然这点CSS肯定想到了,在弄明白这个冲突前我们先来看一下div元素水平方向7
属性的默认值。
div元素水平方向7属性的默认值是这样




width为auto,padding-left、padding-right、border-left、border-right为0,margin-
left、margin-right为auto。

可以看到这里有3个属性的默认值为auto,在这7个属性里也只有这3个属性的值可
以设为auto。

这个auto是什么意思呢?

前面说过水平方向7属性之和就等于父元素的width值,这个auto的作用就是弥补其
他部分之和与父元素width值之间的差别。
再看下前面这段代码

<div id="div1" style="width:400px;">
   <div id="div2" style="margin-left:10px;margin-right:10px;padding-
left:10px;padding-right:10px;border-left:10px solid;border-right:10px solid
blue;width:auto;">CSS盒模型</div>
</div>

如果将div2的width值设为auto,其它6属性的值都设为10px,那么这个时候div2的
width值为:400px - 60px = 340px,这就是auto的意义,弥补其他部分之和与父元
素width值之间的差别。

我们可以再试着这样做

<div id="div1" style="width:400px;">
  <div id="div2" style="width:200px;margin-left:150px;margin-right:auto;">CSS盒
模型</div>
</div>

将div2的width设为200px,margin-left设为150px,margin-right设为auto,那么这
里的计算就更简单了,margin-right值 = 400px - 200px - 150px = 50px。
前面示例中都只定义一个值为auto,那如果有两个值或三个值设为auto
会是什么情况呢?

<div id="div1" style="width:400px;">
  <div id="div2" style="width:200px;margin-left:auto;margin-right:auto;">CSS盒模
型</div>
</div>

这里将div2的width值设为200px,margin-left和margin-right的值设为auto,这时候
margin-left + margin-right = 400px - 200px = 200px,而这个200px会由margin-left
和margin-right进行平分,各得100px,这样就会让div2在div1中水平居中(注意这
里说的是核心内容区的水平居中,并不是元素框),其实这就是将一个元素水平居
中是正确方式,也是我们常用的一个方法。

那如果margin-left或margin-right和width值设为auto时会是怎样的效果呢?

<div id="div1" style="width:400px;">
  <div id="div2" style="width:auto;margin-left:auto;margin-right:100px;">CSS盒模
型</div>
</div>
这时值为auto的margin就会降为0,也就像只有width值设为auto一样,
width = 400px - 100px = 300px,将margin-right和width设为auto也是
同样的道理。

那么如果将width、margin-left、margin-right都设为auto会是什么效果呢,其实和前
面一样,margin-left、margin-right会降为0,剩下的就是width值了。

OK,再回到前面没有解决的问题,如果各属性之和比父元素的width值大或是比父
元素的宽度值小时该怎么处理呢?这在CSS中就叫做这些格式编排被过紧约束,那
么这个时候margin-right值就被强制设为auto了。

<div id="div1" style="width:400px;">
  <div id="div2" style="width:100px;margin-left:100px;margin-right:100px;">CSS
盒模型</div>
</div>

看看上面这段代码,width、margin-left、margin-right的值都为100px,它们加在一
起就是300px,和需要的总和不一致,这就叫过紧约束,那么这个时候margin-right
值就会强制为auto,margin-right = 400px - 100px - 100px = 200px。
或者像下面这样

<div id="div1" style="width:400px;">
  <div id="div2" style="width:500px;margin-left:100px;margin-right:100px;">CSS
盒模型</div>
</div>

div2的width + margin-left + margin-right大于400px,这同样是过紧约束,那
margin-right就会强制为auto,margin-right = 400px - 500px - 100px = -200px,注
意,这里出现负值了,在这7个属性中只是margin可以为负值,其他几个属性的值
必须大于0,正是这个负值让盒模型变得复杂起来,这个负值也能让我们实现更丰
富的布局效果。

先看下margin-top和margin-bottom设为负值的情况。

margin-top、margin-bottom相对于margin-left、margin-right有一些特别之处,在页
面上两个垂直相邻元素的margin是会进行合并的。
<div id="div1" style="margin-bottom:10px;">CSS盒模型</div>
<div id="div2" style="margin-top:20px;">CSS盒模型</div>

例如上面这种情况,div1的margin-bottom是10px,div2的margin-top是20px,但两
行文本间的距离并不是30px,而是20px,因为它们是紧挨在一起的,所以div1的
margin-bottom和div2的margin-top并不是相加,而是进行了合并,合并后会取其中
较大的一个值。

当然这种情况只出现在垂直相邻的块级元素上,而且这个块级元素并没有浮动、也
没有绝对定位或固定定位。

那如果是负margin值会怎么计算呢?

<div id="div1" style="margin-bottom:-10px;">CSS盒模型</div>
<div id="div2" style="margin-top:20px;">CSS盒模型</div>

div1的margin-bottom是-10px,div2的margin-top是20px,那这两个元素内容区之
间的距离就是20 + -10px = 10px。
如果负值比正值更大,那可能就会出现内容区重叠的情况

<div id="div1" style="margin-bottom:-30px;">CSS盒模型</div>
<div id="div2" style="margin-top:20px;">CSS盒模型</div>

如果像上面这样定义,那这两个元素之间的间距就是 -30px + 20px = -10px,这样
它们就会有10px重叠。
那如果垂直方向相邻的两个margin都是负值会是什么效果呢

<div id=“div1” style=“margin-bottom:-30px;”>CSS盒模型</div>
<div id=“div2” style=“margin-top:-20px;">CSS盒模型</div>

上面这样div1的margin-bottom是-30px,div2的margin-top是-20px,同样它们会进
行合并,合并后会取较小那个那值,也就是-30px。

再看看水平方向有负margin的情况

<div id=“div1” style=“width:400px;padding:10px 0;”>
  <div id=“div2” style=“width:auto;margin-left:auto;margin-right:-100px;”>CSS盒模
型</div>
</div>

div2中width和margin-left的值都是auto,这个时候margin-left的值就会降为0,
width值 = 400px - (-100px) = 500px,这样核心内容区的宽度就比父元素还要宽,
但实际元素框的宽度还是400px,只是核心内容区有一部分延伸到了元素框之外了,
这并不违背前面的定义,水平方向7属性之和始终等于父元素的width值。
这个元素框可以称之为元素的逻辑大小,而我们所看到的width和
height定义的核心内容区可以称之为元素的物理大小,元素在页面上是
按逻辑大小进行排列的,所以前面看到的div2元素的核心内容区虽然超出了
元素框,但这不会影响其它相邻元素的排列,影响相邻元素排列的只是这个元素的
逻辑大小,也就是元素框的大小。

OK,对CSS盒模型的介绍就到这里,这部分内容更多的是理论方面的东西,要真正
掌握还需要大家在实践中不断总结。
这一部分要讲的并不是该怎么切图、怎么写代码来实现这个设计效果,我只是以
上面这个菜单为例来说说我实现这个菜单的一些思路。

这个菜单的样式分为三部分:

# 文本样式 (字体系列、字体尺寸等等)

# 色彩样式 (文本颜色、背景等等)

# 布局样式 (菜单的整体宽度、高度,菜单项的大小等等)

这三部分样式并不是相对独立的,文本的样式会影响菜单项的大小,菜单项的大
小会影响这些色彩所应用的范围。这些因素也决定着怎样为一个元素定义width、
height、margin等等这些属性。

很多时候我们是以一个元素的内容和色彩来判断这个元素的大小的;除此之外还
有元素与元素之间的关系;如果这是一个功能性的元素,如:链接、Tab效果中
的标签等等,那这个元素的鼠标感应区域也会影响我们对这个元素的大小的定义。
上面这个菜单的整体大小很容易判断,就是圆角灰色图片显示的范围。

菜单项的大小该怎么判断呢,如果不考虑鼠标划过时的变化,菜单项在默认状态下
没有border、背景等等这些样式,只是纯粹的文本,这个时候它的大小就由文字和
你觉得合适的鼠标点击区域来决定了。但在鼠标划过时有一个背景,那判断菜单项
的大小时就需要把这个背景考虑在内,因为菜单项的大小决定其背景所能应用的范
围,所以要让鼠标划过时完整的显示这个背景,菜单项的大小就至少是这个背景图
片所显示的范围。

在这里还可以看到鼠标划过菜单项时,菜单项的背景和菜单整体下边缘之间有一定
的距离,这个间距该怎么实现呢,有两种方法,为菜单整体定义一个padding-
bottom,或者为每个菜单项定义一个margin-bottom,这两种方法都能实现这个效果,
那用哪种更合适呢,我更倾向于使用第一种方法,为菜单整体定义一个padding-
bottom。
上面这个菜单的整体大小很容易判断,就是圆角灰色图片显示的范围。

菜单项的大小该怎么判断呢,如果不考虑鼠标划过时的变化,菜单项在默认状态
下没有border、背景等等这些样式,只是纯粹的文本,这个时候它的大小就由文
字和你觉得合适的鼠标点击区域来决定了。但在鼠标划过时有一个背景,那判断
菜单项的大小时就需要把这个背景考虑在内,因为菜单项的大小决定其背景所能
应用的范围,所以要让鼠标划过时完整的显示这个背景,菜单项的大小就至少是
这个背景图片所显示的范围。

在这里还可以看到鼠标划过菜单项时,菜单项的背景和菜单整体下边缘之间有一
定的距离,这个间距该怎么实现呢,有两种方法,为菜单整体定义一个padding-
bottom,或者为每个菜单项定义一个margin-bottom,这两种方法都能实现这个
效果,那用哪种更合适呢,我更倾向于使用第一种方法,为菜单整体定义一个
padding-bottom。
有两个原因:首先这个间距应该是菜单整体对菜单项所占空间的一个限制,那么
这地方直接为菜单整体定义一个padding-bottom来实现这个限制应该更合适;还
有一点就是用这种方式只需要为一个元素定义这个属性,而如果为每个菜单项定
义一个margin-bottom值,虽然在CSS中同样只需要定义一次,但浏览器却需要
对多个元素进行渲染,从性能上说前一种方法更好,虽然这个性能的差异会很小
(不过这方面我没验证过,是根据一些资料推断的?),但我们不应该忽略这些
细节方面的东西。

当然这里还有一种情况,你可能会希望菜单项的鼠标感应区域能延伸到菜单的底
部,也就是除了前面鼠标划过时的背景区域外,下边的间距也是菜单项可以点击
的区域,那这个时候就不能为菜单整体定义一个padding-bottom值来实现这个效
果了。

在用颁厂厂布局时没有哪一种方案是最好的,你可能会找到实现某一个布局的好方
法,但如果其中有一些因素变化时这个方法可能就不合适了,所以在实现某个布
局时需要考虑视觉、功能各方面的因素后选择一种更合适的方案。
OK,对颁厂厂布局的讲解就到这里
有兴趣的同学可以试着用我前面所说的一些思路来分析下这个菜
         单,写html和CSS来实现这个菜单的效果。
设计稿:http://www.butong.net/exercise/css/exercise3/menu.gif

                      谢谢 ?

More Related Content

颁蝉蝉布局