续上一篇,接下来记录的是定位元素。

第3章 定位元素

本章,我们该学习盒模型了。当然,还有position和display属性,以及如何浮动(float)和清除(clear)元素。这么说吧,要掌握CSS技术,核心就是要掌握元素定位,只有这样才能用CSS创造出专业水准的页面布局。

盒模型

所谓盒模型,就是浏览器为页面中的每个HTML元素生成的矩形盒子。这些盒子们都要按照可见版式模型(visual formatting model)在页面上排布。可见的页面版式主要由三个属性控制:position属性、display属性和float属性。其中,position属性控制页面上元素间的位置关系,display属性控制元素是堆叠、并排,还是根本不在页面上出现,float属性提供控制的方式,以便把元素组成成多栏布局。

元素盒子的属性可以分成三组:

  • 边框(border)。可以设置边框的宽窄、样式和颜色。
  • 内边距(padding)。可以设置盒子内容区与边框的间距。
  • 外边距(margin)。可以设置盒子与相邻元素的间距。

CSS为边框、内边距和外边距分别规定了简写属性,让你通过一条声明就可以完成设定。在每个简写声明中,属性值的顺序都是上、右、下、左。想象一下顺时针旋转就记住了。

边框(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规定边框的角度。

推荐大家把下面这条规则作为样式表的第一条规则:

* {margin:0; padding:0;}

这条规则把所有元素默认的外边距和内边距都设定为零。把这条规则放到样式表里后,所有默认的外边距和内边距都会消失。然后,你可以为那些真正需要外边距的元素再添加外边距。

垂直方向上的外边距会叠加,这可是你必须得知道的一件事。举个例子,假设有3个段落,前后相接,而且都应用以下规则:

/*为简明起见,省略了字体声明*/
p {height:50px; border:1px solid #000; 
  backgroundcolor:#fff; 
  margin-top:50px; 
  margin-bottom:30px;}

由于第一段的下外边距与第二段的上外边距相邻,你自然会认为它们之间的外边距是80像素(50+30),但是你错啦!它们实际的间距是50像素。像这样上下外边距相遇时,它们就会相互重叠,直至一个外边距碰到另一个元素的边框。就上面的例子而言,第二段较宽的上外边距会碰到第一段的边框。也就是说,较宽的外边距决定两个元素最终离多远,没错——50像素。这个过程就叫外边距叠加。

注意啦,叠加的只是垂直外边距,水平外边距不叠加。对于水平相邻的元素,它们的水平间距是相邻外边距之和。这跟你最初想的一样。

为什么要让外边距叠加呢?如果有一连串段落都被应用了相同的样式,那么对其中第一段和最后一段来说,它们的上外边距和下外边距决定了它们与包含元素的间距。而那些位于中间的段落呢,根本不需要两个外边距加起来那么宽的间距。因此,就像图3-7所示的那样,相邻的外边距叠加起来是最合理的,哪个外边距宽,就以哪个外边距作为段间距。

根据经验,为文本元素设置外边距时通常需要混合使用不同的单位。比如说,一个段落的左、右外边距可以使用像素,以便该段文本始终与包含元素边界保持固定间距,不受字号变大或变小的影响。而对于上、下外边距,以em为单位则可以让段间距随字号变化而相应增大或缩小,比如:

/*这里使用了简写属性把上、下外边距设置为.75em,把左、右外边距设置为30像素*/
p {font-size:1em; margin:.75em 30px;}

这样,段落的垂直间距始终会保持为字体高度的四分之三(上下外边距都是.75em,叠加后还是.75em)。如果用户增大了字号,那么不仅段落中的文本会变大,段间距也会成比例变大。这样,页面的整体布局就会比较协调一致。与此同时,使用像素单位的左、右外边距不会改变。我想,你应该也不会想让字号变化影响到布局宽度吧。

盒子有多大

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

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

浮动与清除

浮动和清除是用来组织页面布局的又一柄利剑,这柄剑的剑刃就是float和clear属性。浮动,你看这俩字儿多形象,意思就是把元素从常规文档流中拿出来。拿出来干什么?一是可以实现传统出版物上那种文字绕排图片的效果,二是可以让原来上下堆叠的块级元素,变成左右并列,从而实现布局中的分栏。

浮动元素脱离了常规文档流之后,原来紧跟其后的元素就会在空间允许的情况下,向上提升到与浮动元素平起平坐。

如果浮动元素后面有两个段落,而你只想让第一段与浮动元素并列(就算旁边还能放下第二段,也不想让它上来),怎么办?用clear属性来“清除”第二段,然后它就乖乖地呆在浮动元素下面了。

CSS设计float属性的主要目的,是为了实现文本绕排图片的效果。然而,这个属性居然也成了创建多栏布局最简单的方式。

1、 文本绕排图片.

<img …… />
<p>…the paragraph text…</p>
/*为简明起见,省略了字体声明*/
p {margin:0; border:1px solid red;}
/*外边距防止图片紧挨文本*/
img {float:left; margin:0 4px 4px 0;}

说得形象一点,在你浮动一张图片或者其他元素时,你是在要求浏览器把它往上方推,直到它碰到父元素(也就是body元素)的内边界。后面的段落(带灰色边框)不再认为浮动元素在文档流中位于它的前面了,因而它会占据父元素左上角的位置。不过,它的内容(文本)会绕开浮动的图片。

浮动非图片元素时,必须给它设定宽度,否则后果难以预料。图片无所谓,因为它本身有默认的宽度。

2、 创建分栏

在此基础上创建多栏,只要再用一次float属性,就这么简单。

p {float:left; margin:0; width:200px; border:1px solid red;}
img {float:left; margin:0 4px 4px 0;}

你这样同时浮动图片和“有宽度的”段落,会导致段落的文本绕排效果消失,而浮动的段落也会尽可能向左向上移动。就这样,这个段落就构成了紧挨着图片的一栏。这就是使用float属性创建多栏布局的原理。换句话说,如果几个相邻的元素都具有设定的宽度,都是浮动的,而且水平空间也足以容纳它们,它们就会并列排在一行。如果你创建了三个浮动、固定宽度的元素,它们就会像这样并排在一行,构成三栏布局的框架。每个元素都可以作为容器,包含其他元素。

3、 围住浮动元素的三种方法

浮动元素脱离了文档流,其父元素也看不到它了,因而也不会包围它。这种情况有时候并非我们想要的,本节向大家传授三种围住浮动子元素的方法。记住,这三种方法你都得掌握,这样才能审时度势,选择最合适的一种。

  • 方法一:为父元素添加overflow:hidden。
  • 方法二:同时浮动父元素。
  • 方法三:添加非浮动的清除元素,可以直接在标记中加,也可以通过给父元素添加clearfix类来加(当然,样式表中得需要相应的clearfix规则)。

定位

CSS布局的核心是position属性,对元素盒子应用这个属性,可以相对于它在常规文档流中的位置重新定位。position属性有4个值:static、relative、absolute、fixed,默认值为static。相对定位相对的是它原来在文档流中的位置(或者默认位置)。绝对定位跟静态定位和相对定位比,绝对不一样。因为绝对定位会把元素彻底从文档流中拿出来。固定定位从完全移出文档流的角度说,与绝对定位类似。但不同之处在于,固定定位元素的定位上下文是视口(浏览器窗口或手持设备的屏幕),因此它不会随页面滚动而移动。

把元素的position属性设定为relative、absolute或fixed后,继而可以使用top、right、bottom和left属性,相对于另一个元素移动该元素的位置。这里的“另一个元素”,就是该元素的定位上下文。

在讲绝对定位的时候,我们知道绝对定位元素默认的定位上下文是body。这是因为body是标记中所有元素唯一的祖先元素。而实际上,绝对定位元素的任何祖先元素都可以成为它的定位上下文,只要你把相应祖先元素的position设定为relative即可。

显示属性

正如所有元素都有position属性,所有元素也都有display属性。尽管display属性的值有很多,但大多数元素display属性的默认值不是block,就是inline。

  • 块级元素,比如段落、标题、列表等,在浏览器中上下堆叠显示。
  • 行内元素,比如a、span和img,在浏览器中左右并排显示,只有前一行没有空间时才会显示到下一行。

把块级元素变成行内元素(或者相反)的魔法如下。

/*默认为block*/
p {display:inline;}
/*默认为inline*/
a {display:block;}

display属性还有一个值有必要提一下,就是none。把元素的display设定为none,该元素及所有包含在其中的元素,都不会在页面中显示。它们原先占据的所有空间也都会被“回收”,就好像相关的标记根本不存在一样。与此相对的是visibility属性,这个属性最常用的两个相对的值是visible(默认值)和hidden。把元素的visibility设定为hidden,元素会隐藏,但它占据的页面空间仍然“虚位以待”。

背景

  • background-color
  • background-image
  • background-repeat
  • background-position
  • background-size
  • background-attachment
  • background(简写属性)
  • background-clip、 background-origin、background-break(目前尚未得到广泛支持)

背景图片——默认情况下背景图片会以元素左上角为起点,沿水平和垂直方向重复出现,最终填满整个背景区域。正是因为以元素左上角为原点,所以元素盒子底部和右侧的圆形图案都只显示了一部分。要注意的是,指定背景图片来源的方式,与img标签中的方式不同,要这样:

background-image:url(图片路径/图片文件名)

要改变默认的水平和垂直重复效果,可以修改background-repeat属性;要改变背景图片的起点,可以修改background-position属性。

背景重复——控制背景重复方式的background-repeat属性有4个值。默认值就是repeat,效果就是图3-34中所示的水平和垂直方向都重复,直至填满元素的背景区域为止。另外3个值分别是只在水平方向重复的repeat-x、只在垂直方向上重复的repeat-y和在任何方向上都不重复(或者说只让背景图片显示一次)的no-repeat 。

在此之前先提醒大家一句,CSS3还规定另外两个值(但尚未得到浏览器支持),以控制背景图片重复确切的次数,即所有图片都是完整的,不会出现半张图片的现象。

  • background-repeat:round:为确保图片不被剪切,通过调整图片大小来适应背景区域。
  • background-repeat:space,为确保图片不被剪切,通过在图片间添加空白来适应背景区域。

背景位置——用于控制背景位置的background-position属性,是所有背景属性中最复杂的。background-position属性有5个关键字值,分别是top、left、bottom、right和center,这些关键字中的任意两个组合起来都可以作为该属性的值。比如,top right表示把图片放在元素的右上角位置,center center把图片放在元素的中心位置。

设定背景位置时可以使用三种值:关键字、百分比、绝对或相对单位的数值。可以使用两个值分别设定水平和垂直位置。

  1. 关键字指的顺序不重要,left bottom和bottom left意思相同。为了设定的值在所有浏览器中都有效,最好不要混用关键字值与数字值。
  2. 使用数值(比如40% 30%)时,第一个值表示水平位置,第二个值表示垂直位置。要是只设定一个值,则将其用来设定水平位置,而垂直位置会被设为center。在使用关键字和百分比值的情况下,设定的值同时应用于元素和图片。换句话说,如果设定了33% 33%,则图片水平33%的位置与元素水平33%的位置对齐。垂直方面也一样。
  3. 像素之类的绝对单位数值就不一样了。要是用像素单位来设定位置,那么图片的左上角会被放在距离元素左上角指定位置的地方。有意思的是,还可以使用负值。这样就可以把图片的左上角定位到元素外部,从而在元素中只能看到部分图片。当然,给图片设定足够大的正值,也可以把图片的右下角推到元素外部,从而在元素中也只能看到部分图片。位于元素外部的那部分图片不会显示。

背景尺寸——CSS3规定的属性,但却得到了浏览器很好的支持。这个属性用来控制背景图片的尺寸,可以给它设定的值及含义如下:

  • 50%:缩放图片,使其填充背景区的一半。
  • 100px 50px:把图片调整到100像素宽,50像素高。
  • cover:拉大图片,使其完全填满背景区;保持宽高比。
  • contain:缩放图片,使其恰好适合背景区;保持宽高比。

背景粘附——background-attachment属性控制滚动元素内的背景图片是否随元素滚动而移动。这个属性的默认值是scroll,即背景图片随元素移动。如果把它的值改为fixed,那么背景图片不会随元素滚动而移动。

background-attachment:fixed最常用于给body元素中心位置添加淡色水印,让水印不随页面滚动而移动。

多背景图片

p {
    height:150px;
    width:348px;
    border:2px solid #aaa;

    margin:20px auto;
    font:24px/150px helvetica, arial, sansserif;
	text-align:center;
    background:
    url(images/turq_spiral.png) 30px -10px no-repeat,
    url(images/pink_spiral.png) 145px 0px no-repeat,
    url(images/gray_spiral.png) 140px -30px no-repeat, #ffbd75;
 }

在CSS中,我把每张图片的声明都单独放在了一行里,以逗号分隔,以便看清它们的位置、重复的设定值。为了防止图片加载失败时元素背景处于默认的透明状态,这里也在最后一条声明中加上了背景颜色(加粗的值)。要注意的是,代码中先列出的图片显示在上方,或者说,更接近前景。

厂商前缀——为鼓励浏览器厂商尽早采用W3C的CSS3推荐标准,于是就产生了VSP(Vendor Specific Prefixes,厂商前缀)的概念。

有了这些CSS属性的前缀,厂商就可以尝试实现W3C涵盖新CSS属性的工作草案。在迅速实现新属性的同时,还可以声明它们是过渡的、部分实现的,或者实验性的。总之,后果由使用者自负。 就拿W3C推荐的transform属性为例,标准语法是这样的:

transform: skewX(-45deg);

然而,由于这个属性还没有完全定案,为保证在大多数浏览器以及它们的实验性实现中能够使用这个属性,应该针对想要支持的浏览器为该属性添加VSP。每个浏览器只使用各自能理解的属性声明。

-moz-transform:skewX(-45deg);    /* Firefox */
-webkit-transform:skewX(-45deg); /* Chrome及Safari */
-ms-transform:skewX(-45deg);     /* 微软Internet Explorer */
-o-transform:skewX(-45deg);      /* Opera */
transform:skewX(-45deg);         /* 最后是W3C标准属性 */

VSP的开头是一个连字符,然后是前缀名,接着又是一个连字符,最后是W3C属性名。另外要特别注意,在带前缀的属性声明之后还要声明W3C标准属性,以备将来有浏览器实现完整的不带前缀的属性时派上用场。这里的Safari和Chrome都使用相同的-webkit-前缀,是因为它们都使用Webkit渲染引擎。

以下CSS3属性必须加VPS:

border-image       translate
linear-gradient    transition 
radial-gradient    background*
transform          background-image*
transform-origin
* 针对背景图片或渐变

背景渐变——渐变分两种,一种线性渐变,一种放射性渐变。线性渐变从元素的一端延伸到另一端,放射性渐变则从元素内一点向四周发散。

  1. 渐变点。渐变点就是渐变方向上的点,可以在这些点上设定颜色和不透明度。通过设定下一个渐变点的颜色值,就可以控制渐变的效果。可以添加任意多个渐变点。渐变点的位置一般使用整个渐变宽度的百分比来表示。
  2. 放射性渐变。放射性渐变比线性渐变复杂那么一点点,因为可用的控制点多一些。如果你写过程序,从属性值中的括号就可以看出,渐变属性其实是函数。什么是函数?函数可以接收参数,然后根据这些参数来生成渐变。在创建放射性渐变时,可以使用参数指定形状、位置、尺寸、颜色和不透明度。 下面的每一个例子都设定3种颜色。