27
CSS 布布 2010.06.29 十十十 [email protected]

Css布局

Embed Size (px)

DESCRIPTION

本文档介绍了一些CSS布局方面的知识,内容分为两部分: CSS盒模型,这是CSS布局的基础,是学习CSS需要了解的几个最重要的概念之一。 实例分解,这部分讲一些我在CSS布局方面的一些思路。

Citation preview

Page 1: Css布局

CSS 布局 2010.06.29

十年磨一剑 [email protected]

Page 2: Css布局

本文档的内容分为两部分

• CSS 盒模型• 实例分解

Page 3: Css布局

CSS盒模型什么是 CSS 盒模型?

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

它决定着一个元素在页面上的大小,也决定着margin、 padding等等这些 CSS

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

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

的能力,因为这会让我们更多的了解 bug背后的为什么,而不是遇到一个 bug时就到处找资料、找解决方法。

Page 4: Css布局

CSS盒模型前面说过 CSS盒模型决定着margin、 padding等等这些属性怎么影响一个元素,那么下面就用一个我们最常用 div标签来理解 CSS盒模型,了解这些属性是怎么影响元素的。

看看下面这段代码

<div>CSS 盒模型 </div>

一个 div 开始标签和一个 div 结构标签包裹着一段文本,这在 html 中就称为一个div 元素,把这段代码加到一个 html 文件中,在我们没定义样式情况下浏览器会怎样显示呢?

Page 5: Css布局

CSS盒模型很简单,就一行文本,没有边框也没有背景,或者我们可以为它加一个padding属性,像下面这样。

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

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

在添加了一个 padding 后再看看浏览器是怎么显示的。

Page 6: Css布局

CSS盒模型我们能看到的其实还是一行文本,只是文本周围多了一些空白,但浏览器并不是像我们这样来 "看 "这个元素的。

元素框( element box )

CSS 假定每个元素都会生成一个矩形框,术语称之为“元素框( element bo

x )”,元素框的大小由 4 部分属性决定: width与 height、 padding、 border

和margin ,前面那个 div 元素在添加一些 padding 后,它的元素框的大小会是下面这样子。

Page 7: Css布局

CSS盒模型或者我们可以再为它定义一些margin和 border,像下面这样:<div style="margin:30px;padding:30px;border:solid 30px blue;">CSS

盒模型 </div>

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

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

Page 8: Css布局

CSS盒模型

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

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

实际元素框的大小是这样

Page 9: Css布局

CSS盒模型看看下面这幅画

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

Page 10: Css布局

CSS盒模型一个元素框在页面上所占的空间是怎么计算的呢?

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

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

+ padding-top + padding-bottom

这 7 个属性值的总和就等于元素框的高度。如果 margin、 border、 padding 这些值为 0 时,这个元素的高度就由 height 值来决定了,但页面上的元素大多没有定义一个固定的 height 值的,那么这个时候元素框的高度就是由内容来决定的。就像我们前面看到的那个 div 元素,在没定义样式时它的高度就由内容决定。

Page 11: Css布局

CSS盒模型

上面是浏览器所显示的效果,下面的黄色背景区域就是元素框的实际大小了

Page 12: Css布局

CSS盒模型同样,元素框的宽度也是由 7个属性决定

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

ing-left + padding-right

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

Page 13: Css布局

CSS盒模型看看下面这段代码

<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 属性的默认值。

Page 14: Css布局

CSS盒模型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 值之间的差别。

Page 15: Css布局

CSS盒模型再看下前面这段代码

<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 。

Page 16: Css布局

CSS盒模型前面示例中都只定义一个值为 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>

Page 17: Css布局

CSS盒模型这时值为 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 。

Page 18: Css布局

CSS盒模型或者像下面这样

<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 是会进行合并的。

Page 19: Css布局

CSS盒模型<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 。

Page 20: Css布局

CSS盒模型如果负值比正值更大,那可能就会出现内容区重叠的情况

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

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

如果像上面这样定义,那这两个元素之间的间距就是 -30px + 20px = -10px ,这样它们就会有 10px 重叠。

Page 21: Css布局

CSS盒模型那如果垂直方向相邻的两个 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 值。

Page 22: Css布局

CSS盒模型这个元素框可以称之为元素的逻辑大小,而我们所看到的 width 和height 定义的核心内容区可以称之为元素的物理大小,元素在页面上是按逻辑大小进行排列的,所以前面看到的 div2 元素的核心内容区虽然超出了元素框,但这不会影响其它相邻元素的排列,影响相邻元素排列的只是这个元素的逻辑大小,也就是元素框的大小。

OK ,对 CSS 盒模型的介绍就到这里,这部分内容更多的是理论方面的东西,要真正掌握还需要大家在实践中不断总结。

Page 23: Css布局

实例分解

这一部分要讲的并不是该怎么切图、怎么写代码来实现这个设计效果,我只是以上面这个菜单为例来说说我实现这个菜单的一些思路。

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

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

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

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

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

很多时候我们是以一个元素的内容和色彩来判断这个元素的大小的;除此之外还有元素与元素之间的关系;如果这是一个功能性的元素,如:链接、 Tab 效果中的标签等等,那这个元素的鼠标感应区域也会影响我们对这个元素的大小的定义。

Page 24: Css布局

实例分解

上面这个菜单的整体大小很容易判断,就是圆角灰色图片显示的范围。

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

在这里还可以看到鼠标划过菜单项时,菜单项的背景和菜单整体下边缘之间有一定的距离,这个间距该怎么实现呢,有两种方法,为菜单整体定义一个 padding-

bottom ,或者为每个菜单项定义一个 margin-bottom ,这两种方法都能实现这个效果,那用哪种更合适呢,我更倾向于使用第一种方法,为菜单整体定义一个padding-bottom 。

Page 25: Css布局

实例分解

上面这个菜单的整体大小很容易判断,就是圆角灰色图片显示的范围。

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

在这里还可以看到鼠标划过菜单项时,菜单项的背景和菜单整体下边缘之间有一定的距离,这个间距该怎么实现呢,有两种方法,为菜单整体定义一个padding-bottom ,或者为每个菜单项定义一个 margin-bottom ,这两种方法都能实现这个效果,那用哪种更合适呢,我更倾向于使用第一种方法,为菜单整体定义一个 padding-bottom 。

Page 26: Css布局

实例分解

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

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

在用 CSS 布局时没有哪一种方案是最好的,你可能会找到实现某一个布局的好方法,但如果其中有一些因素变化时这个方法可能就不合适了,所以在实现某个布局时需要考虑视觉、功能各方面的因素后选择一种更合适的方案。

Page 27: Css布局

OK,对 CSS布局的讲解就到这里

有兴趣的同学可以试着用我前面所说的一些思路来分析下这个菜单,写 html和 CSS 来实现这个菜单的效果。

设计稿: http://www.butong.net/exercise/css/exercise3/menu.gif

谢谢