CSS 的静态和相对定位

在这篇文章中我要开始深入地探讨如何利用CSS来随心所欲地定位HTML元素,我们要用到position CSS属性和其它一些相关的属性。

在CSS中,position属性有四个合法的属性值(除大家都有的inherit):
static, relative, absolutefixed
staticrelative这两个值密切相关,我们将在本文中对它们进行详尽地讨论。同样,
absolutefixed这两个属性值也是紧密相关的,我将它们安排在本系列的下一篇文章中讨论。

本文结构如下:

精彩的矩形世界

我们先来回顾一下第35篇文章:浮动元素与清除中讨论过的CSS与HTML盒模型。HTML文档包含了夹杂着字符数据(文本)的若干元素。当这样一份文档渲染在计算机屏幕上或者打印在纸上的时候,这些元素就会生成矩形盒模型。就像HTML元素分为块级元素和内联元素一样,CSS中的盒模型实质上也有区块盒模型和内联盒模型之分。在默认情况下,浏览器中的嵌入式用户代理样式表会使pdiv之类的HTML元素生成区块盒模型,而strongspan之类的内联元素则生成内联盒模型。我们可以通过display属性来控制生成的盒模型的类型。

由HTML文档中的元素生成的盒模型将按照
CSS2.1 规范所明确定义的法则来进行布局。这些法则针对的是少数编写浏览器来研究CSS工作原理的人,而不是针对我们这些靠设计网页谋生的人或网页设计爱好者。这就是本系列教程的意义所在!由于上述的原因,这个规范可能会有些艰深。在本文中我将以更适合网页设计师和开发员的方式来讲解这些基本原理。

静态定位

这个名称还真是用词不当。从CSS的意义上讲,设置了position:static的盒模型实际上根本没有“被定位”。它们的排列顺序就是自身在HTML标记中的顺序,同时它们会占据自身所需的空间——这其实就是没有应用CSS时HTML文档的默认效果。

区块盒模型的布局和内联盒模型的布局之间有本质上的不同,我们将分别对这两种类型进行研究。因为区块盒模型比较简单,我们就从它开始:

块状盒模型布局

如果我们没有应用特定的CSS声明的话,区块盒模型会按照它们在HTML标记中的出现顺序从上到下垂直排列。每个盒模型通常都是与HTML文档(body元素)等宽的,但就算我们把它们变窄一点,留出空间来,它们也不会一个挨一个横着排列;还是会一个接一个竖着排列。你可以想象它们前后都有隐式的换行符,使得每个盒模型都独占一“行”。

两个盒模型之间的纵向距离是由第一个盒模型的margin-bottom属性和第二个盒模型的margin-top属性控制的(之前你已经学过了如何操纵这两个属性)。对于常规数据流中的盒模型,例如不浮动的盒模型或绝对定位的盒模型,两个相邻块状盒模型的垂直边距会发生合并——也就是部分重叠——因此最终结果并不是两个边距的和,而是二者之中较大的那个边距,如图1所示。

看看下面的HTML代码片段:

<p style="margin-bottom:40px">This paragraph has a 40px bottom margin.</p>
<p style="margin-top:20px">This paragraph has a 20px top margin.</p>

在浏览器中观看时,边距将会产生合并,如图1所示:

The distance between the two paragraphs is 40px not 60px

图1:边距合并——上下两个盒模型之间的距离成了40px,而不是60px。

一个块状盒模型可能只包含其它块状盒模型,或者只包含内联盒模型。如果一个块级元素既包含块级子元素又包含内联子元素——这种情况是允许的,但会产生一种所谓的匿名块状盒模型来将内联子盒模型包含其中,因此父盒模型就只包含块状盒模型了。

你可以通过widthheight属性来指定块状盒模型的大小,还可以对其进行垂直边距和水平边距的设置。widthheight属性的初始(默认)值为auto,而边距的初始值为0.这些值综合在一起就意味着块状盒模型在默认情况下是与其父盒模型等宽的,如图2所示:

Block boxes are laid out vertically

图2:块状盒模型的排列是垂直的。

内联盒模型布局

对于CSS新手来说本章可能会比较艰深,但如果你第一遍没有读懂的话也不用灰心。,对于深入了解这些问题来说,自己下来多多尝试是最好的办法——不过你应该选用一种比较好而且标准兼容的浏览器来进行实验,比如说Opera或Firefox之类的。

内联盒模型默认是由内联HTML元素生成的,也同样会产生匿名内联盒模型来包含某些元素的文本内容。

内联盒模型的排列是水平的,按照它们在HTML标记中出现的顺序依次排列。direction属性决定了内联盒模型的排列方向,当direction属性为direction:ltr时内联盒模型从左到右排列,而当direction属性为direction:rtl时则是从右到左排列。从左到右的方向可用在欧洲语言等的排列上,而从右到左的方向是用在阿拉伯和希伯来之类语言的排列上。

在屏幕上(或纸上)排成一行的内联盒模型又被装在另一个矩形中,这种矩形叫做线框。线框在其块级父盒模型中纵向排列,彼此之间没有空隙。我们可以通过line-height属性来调整线框的高度。

我们不能指定线框的方向。同时只能对其指定水平边距,而不能指定垂直边距。

必要的话,内联盒模型可以由一个分裂成几个,分散在两个或多个线框中。产生分裂时,所有的水平边距和填充距,以及所有垂直边框都只能出现在第一个盒模型之前和最后一个盒模型之后。下面的代码对HTML文档的em元素定义了规则:

em {
  margin: 0 2em;
  padding: 0 1em;
  border: 1px dotted blue;
}

当样式化后的元素分散在多行时,这段代码将会产生图3所示的布局效果:

The margins padding and border do not apply where the breaks occur

图3:在产生分裂的地方无法应用边距,填充距和边框。

vertical-align属性决定了内联盒模型在外围线框中的垂直对齐。该属性的缺省值是baseline,即内联线框的对齐使得其文本基线排成一线。基线是指没有伸尾部分的字母所依照的一条假想线。它位于线框底部之上,并留有一段距离,以便给某些小写字母的下伸部分留下地方,如图4所示:

Letters stand on the imaginary baseline

图4:字母依照着假想的基线排列。

注意,vertical-align属性只能用在线框和表格单元格上,并且不能继承。图5显示了一些在垂直对齐方面各不相同的小图片。

Images placed using settings of the vertical align CSS property

图5:通过CSS属性vertical-align的设置来定位图片。

如果线框中的内联盒模型的总宽度小于该线框自身的宽度,内联盒模型的水平对齐就由text-align属性来控制。必要的话可以通过text-align:justify向内联盒模型之间插入额外的间距, 来使内容两端对齐。这个属性可以应用于块状盒模型,表格的单元格和内联区块,并且可以继承——图6中演示的是将不同的text-align属性值应用于单元格内的文本:

Controlling the alignment of text using the text-align property

图6:通过text-align属性来控制文本的对齐方式。

相对定位

相对定位是CSS中的一种定位模式,但比起它的近亲——绝对定位和固定定位来说,它与静态“定位”的关系更为密切。

设置了position:relative属性的元素最初是像所有块级和内联静态元素一样排列的。但随后就会发生一些有趣的事情:生成的盒模型会按照top, bottom,
leftright这些属性来移动。

需要记住的是,在相对定位下只有生成的盒模型才会移动。而元素在静态文件流中的位置保持不变。对其它元素来说,该元素仍然 “占有空间”。这就是说,被移动的盒模型可能会与其它元素的盒模型相重叠,因为这些元素仍然认为那些应用了相对定位的元素还处在它们原来的位置上,跟应用相对定位之前一样。就文件流而言,元素并没有发生位移——只是最终的视觉效果会显示出盒模型发生了移动。我们来看一个实际的例子。

  1. 在你喜欢的文本编辑器中新建一个文档,将下面的HTML代码拷进去,另存为relative.html

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    
    <html>
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Relative Positioning</title>
      </head>
      <body>
    
        <p>Lorem ipsum dolor sit amet consectetuer adipiscing elit.
        Curabitur feugiat feugiat purus.
        Aenean eu metus. Nulla facilisi.
        Pellentesque quis justo vel massa suscipit sagittis.
        Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos.
        Quisque mollis, justo vel rhoncus aliquam, urna tortor varius lacus, ut tincidunt metus arcu vel lorem.
        Praesent metus orci, adipiscing eget, fermentum ut, pellentesque non, dui.
        Sed sagittis, <span>metus a semper</span> dictum, sem libero sagittis nunc, vitae adipiscing leo neque vitae tellus.
        Duis quis orci quis nisl nonummy dapibus.
        Etiam ante. Phasellus imperdiet arcu at odio.
        In hac habitasse platea dictumst. Aenean metus.
        Quisque a nibh. Morbi mattis ullamcorper ipsum.
        Nullam odio urna, feugiat sed, bibendum sed, vulputate in, magna.
        Nulla tortor justo, convallis iaculis, porta condimentum, interdum nec, arcu.
        Proin lectus purus, vehicula et, cursus ut, nonummy et, diam.</p>
      </body>
    </html>
  2. 浏览器中打开该文件,看看目前的效果——你应该只看到一段普通的文字。

  3. 在文本编辑器中新建一个文档,将下面的CSS代码拷进去,并另存为style.css

    p {
      width: 20em;
    }
    
    span {
      background-color: lime;
    }
  4. 将下面语句插入到</head>标签之前,使该样式表链接到HTML文档中:

    <link rel="stylesheet" type="text/css" href="style.css">
  5. 保存这两个文件,并在浏览器中重新载入页面。我把段落宽度变窄了一点,这样即使浏览器窗口比较小,也能在同样的位置上产生换行符。现在span元素的背景换成了比较鲜艳的颜色,这样它就可以更醒目了。

  6. 接下来,我们修改一下样式表,将下面的三个声明加入到span元素的样式规则中:

    span {
      position: relative;
      top: 1em;
      left: 2em;
      background-color: lime;
    }
  7. 保存文件并在浏览器中重新加载页面,看看相对定位的效果如何。

你同时在垂直方向和水平方向上移动了span元素。注意看,该元素重叠在下一行文本上,而它原先所在的地方空了。

生成盒模型的移动方式可能跟你想的不一样。你指定了top:1em,但盒模型却往下移动了。同样的,你指定了left:2em,该盒模型却被移到了右边。为什么会这样?

要了解这些属性是怎样控制相对定位的,关键是要知道它们指定的不是移动的方向,而是应用该移动的。也就是说,top属性使盒模型相对于其顶边移动,left属性使盒模型相对于其左边移动,等等。该盒模型是从所指定的边移走,因此top:1em是使盒模型从顶部移开1em——也就是说,下移。负数则会使盒模型向相反的方向移动,因此bottom:-1emtop:1em效果相同。

我们可以得出另一个结论:同时为同一个元素指定top属性和bottom属性(或leftright属性)没有意义的。CSS规范规定了如果已经指定了top的话,bottom就会失效。direction属性控制着盒模型的横向移动。在从左到右的条件下,如果同时指定leftright的话,right就会失效;而在从右到左的条件下,left会失效。

刚才我们看到的例子对相对定位进行了一些阐述,但似乎并不是很令人满意,对吧?那么相对定位到底有什么用呢?让我们来看一个更深入的例子。

带源顺序要求的多栏式布局

在这里先提个醒:本例稍微有一点复杂。如果你对CSS不熟悉的话,可能会觉得气馁,但我会慢慢地教你,也会一步一步地解释给你听我到底在做什么。如果你还没有领会第35篇文章(这篇文章讲的是浮动与清除)的内容,现在就是个学习的好机会。

有一种布局类型在网站上非常常见。其构成是这样的:上面是一个页眉,页眉通常包含有一些报头图片,再下面是并排的两个或多个“栏”,再下面是一个全长度页脚,页脚中可能会有版权标注或联系方式。图7展示了这种布局类型的一个示例。

Multiple column layout with header and footer

图7:一个典型的多栏式布局,所有的栏都夹在页眉和页脚之间。

在很早的时候(90年代),这种布局类型通常是通过布局表格来创建的。现在有种为了表面效果滥用HTML标记的倾向,这种做法是不明智的,因此在本教程中我们不会教你这样做。CSS提供了display:table-cell及类似的属性来实现这种布局,但是这种办法有一个很大的缺陷:那就是所有版本的IE目前全都不支持它,所以我们也就不对其进行探讨了。剩下的只有两种选择:浮动元素或绝对定位。这两种方法都各有优缺点,如果你想做一个全长度页脚,但事先又不知道哪一栏最长的话,你就必须用浮动元素来保证页面设计的完整性。

浮动元素的问题在于,它们只能一直向左或向右移动,直到碰到父区块或另一个浮动元素的边沿为止。这意味着浮动栏在HTML标记中的顺序必须正确。但有时我们希望显示顺序跟源顺序不同。比如说,你可能想把目录放在导航之前,来增加键盘导航的易用性,以及改进搜索引擎优化。

  1. 将下面的代码拷到文本编辑器中,另存为layout.html

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
    
    <html lang="en">
      <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <title>Static and Relative Positioning</title>
        <link rel="stylesheet" type="text/css" href="layout.css">
      </head>
    
      <body>
        <div id="header">Header</div>
        <div id="main">Main content</div>
        <div id="sidebar">Sidebar</div>
    
        <div id="nav">Navigation</div>
        <div id="footer">Footer</div>
      </body>
    </html>
  2. 接下来,我们来创建一个样式表的雏形。将下面代码拷到文本编辑器中,另存为layout.css

    #header {
      background-color: #369;
      color: #fff;
    }
    
    #sidebar {
      background-color: #ff6;
    }
    
    #nav {
      background-color: #ddd;
    }
    
    #footer {
      border-top: 1px solid #369;
    }
  3. 保存这两个文件,然后在浏览器中加载页面。可以看到五个部分从上到下依次排列。

    假设你所在的设计部门明确要求导航栏在页面左侧,工具栏在页面右侧,而主要内容栏在页面中间。页眉和页脚应该是跨越整个页面宽度的,但我们不知道三栏中到底哪一栏会是最长的。页面元素的源顺序完全由辅助性和可用性专家们决定,而且没有讨价还价的余地。你该怎样将所有这些要求融合到一个有效的布局中去呢?

    为了满足这些要求,你只有向HTML标记中添加一个附加元素。这是不可避免的,但你应该能忍受多一个附加元素。你需要一个元素来容纳这三个“栏”。

  4. 把下面高亮的两行代码插入到前面的HTML文档中:

    <div id="header">Header</div>
      <div id="wrapper">
        <div id="main">Main content</div>
        <div id="sidebar">Sidebar</div>
    
        <div id="nav">Navigation</div>
      </div>
    <div id="footer">Footer</div>

    设计师们(幸运的是他们了解页面亲和力与设备独立性)约定了导航栏占12em宽,而工具栏占14em。因为固定宽度的布局界面的用户友好性不佳,主要内容栏宽度应该是不固定的,以便适应各种窗口宽度。为了避免文本行过长,妨碍可读性,你需要强制设定该布局约束的最大宽度。同样的,为了避免在极端窄小的窗口中产生重叠现象,你也得强制设定该布局的最小宽度。除了上述约束条件,该布局还应该在浏览器窗口内水平居中。

  5. 接下来,将下面的规则添加到CSS文件的末尾,为导航栏和工具栏设定宽度值,并设置宽度约束和整体居中:

    body {
      margin: 0 auto;
      min-width: 40em;
      max-width: 56em;
    }
    
    #sidebar {
      width: 13em;
      padding: 0 0.5em;
      background-color: #ff6;
    }
    
    #nav {
      width: 11em;
    
      padding: 0 0.5em;
      background-color: #ddd;
    }
  6. 保存文件并重新加载页面——你应该能看到黄色的工具栏和灰色的导航栏元素的宽度符合你的要求。如果浏览器窗口足够大的话,你还可以看到整个页面在宽度上受到了约束,而且页面是水平居中的。

  7. 改变窗口大小,看看该布局是如何适应窗口改变的。

    注意:如果你用的是微软的IE6或更早版本的浏览器,你将看不到任何宽度约束效果。因为这些版本的IE不支持最小和最大宽度(或高度)。在本例结尾的部分我们来看看这个问题的解决办法。事实上,即使是在IE7中运行这个例子,也会产生许多奇怪的效果,因为IE浏览器有很多奇怪的渲染漏洞。下面我会着重从标准兼容方面来分析本例,然后在本文的末尾提出解决办法。

如果你仔细地研究代码的话,将会发现宽度从14em和12em变成了13em和11em。这是因为水平填充距是必需的;你不会希望这些栏的内容与边沿紧紧地挤成一堆,这样的话就不美观了。因此宽度中加上了填充距,13em + 0.5em + 0.5em加起来就等于你所要的14em了。

创建栏

好了,你的基础结构单元已经建好了,但它们还是竖直排列的。你想要的是三栏式的效果,因此现在我们来浮动这些元素。

  1. 将下面代码添加到CSS文件中:

    #main {
      float: left;
    }
    
    #sidebar {
      float: left;
      width: 13em;
      padding: 0 0.5em;
      background-color: #ff6;
    }
    
    #nav {
      float: left;
      width: 11em;
      padding: 0 0.5em;
      background-color: #ddd;
    }

    这段代码浮动了这些元素,但它们的顺序是错的。此外,主要内容栏也太窄了。还有,页脚到底是怎么了?

  2. 我们先来处理一下页脚。页脚的问题在于三个栏都是浮动的,都从文件流中取出来了。页脚被挤得挨着页眉,而包含文本的线框被缩短了,使得“Footer”这个词紧挨在浮动元素的右边。你可以通过对页脚清除所有的浮动栏来纠正这个问题。将下面的代码添加到CSS文件中:

    #footer {
      clear: left;
      border-top: 1px solid #369;
    }
  3. 现在来对付那三个栏。这个问题得一步一步地解决,暂时效果会很难看,但是不要灰心——这个问题最终会获得解决的。

    整个技巧的关键点就是包装元素。我们将对包装元素设置左边距和右边距,其值等于侧边栏(导航栏和工具栏)的宽度。主要内容栏将占据整个包装元素的宽度,而侧边栏将移动到由边距腾出来的空间去。听起来是不是有点复杂?别担心,我会带着你一点一点地前进。首先,我们对包装元素设置边距,将下面规则添加到CSS文件中:

    #wrapper {
      margin: 0 14em 0 12em;
      padding: 0 1em;
    }

    别忘了margin属性值的速记顺序是TRouBLe order: top, right, bottom, left.
    我们将顶部和底部边距设为0,右边距设为14em(工具栏),左边距设为12em(导航栏)。还要添加1em的水平填充距,因为你不会希望内容栏跟侧边栏挤在一起,它需要一点喘息的空间。

  4. 接下来要让主要内容栏占据父包装元素的整个宽度;下面的代码也会暂时给内容栏设置一个鲜艳的背景颜色:

    #main {
      float: left;
      width: 100%;
      background-color: lime;
    }
  5. 保存并重新加载——你将会看到一个鲜艳的石灰绿的内容栏,而工具栏和导航栏在它下方。你也会注意到内容栏两侧有许多空白。我们的技巧就在于将侧边栏塞进这个空白空间去。

    再接下来我们来对付工具栏——它是浮动的,而且宽度是正确的,但由于#main栏占据了100%的宽度,工具栏就被挤到下面去了。怎样才能在#main栏占据全部宽度的情况下让工具栏上升,并放在#main栏旁边呢?我们分成两个小步骤来做:首先,把工具栏上移;然后把它移到边距中去。

  6. 下面我们将用一个妙招来对付浮动的工具栏,它本来是被挤到下面的,现在我们要让它重新搬上去——将下面新增的代码添加到#sidebar规则中:

    #sidebar {
      float: left;
      width: 13em;
      padding: 0 0.5em;
      background-color: #ff6;
      margin-left: -14em;
    }
  7. 保存并重新加载页眉,你可以看到工具栏现在跟内容栏处在同样的垂直层面上了。通过设置一个与工具栏宽度大小相等的负左边距,我们就可以将工具栏元素移回到包装元素中去,这样它就不会被挤下去了。但这里又出现了一个问题,工具栏与内容栏发生了部分重叠。

  8. 你想要的是将工具栏转移到边距那里去,不要再掉下来,在这里相对定位——终于——要登场了。它可以精确地达到我们想要的效果:只移动生成的盒模型,而不移动元素本身。将下面高亮的属性值添加到#sidebar规则中:

    #sidebar {
      float: left;
      width: 13em;
      padding: 0 0.5em;
      background-color: #ff6;
      margin-left: -14em;
      position: relative;
      left: 15em;
    }

    别忘了你应该将工具栏移动15em,而不是14em——因为包装元素还有1em的右填充距。现在工具栏在它该在的地方了:在边距区域中,紧靠着内容栏,与页眉和页脚的右边沿精确地排成一线。

  9. 现在要做的是对导航栏进行同样的操作,虽然用的是一样的方法,但导航栏有自己独特的问题。工具栏的挪动和位移比较简单,移动距离实质上等于其自身的宽度:14em的负边距,然后向右位移14em+1em。但是导航栏得穿越整个内容栏,往边距中位移更多的距离。

    这回我们得使用百分比了。导航栏边距的百分比值是和它的父元素,也就是包装元素成比例的。你应该使导航栏穿越整个包装盒模型——将下面高亮的属性值添加到#nav的规则中去:

    #nav {
      float: left;
      width: 11em;
      padding: 0 0.5em;
      background-color: #ddd;
      margin-left: -100%;
    }
  10. 变!再保存和重新加载一下,你应该能看到导航栏与内容栏的左侧重叠了。现在你只需要将导航栏移到边距中去就可以了。将下面高亮的属性值添加到#nav的规则中去:

    #nav {
      float: left;
      width: 11em;
      padding: 0 0.5em;
      background-color: #ddd;
      margin-left: -100%;
      position: relative;
      right: 13em;
    }

    再说一遍,导航栏的宽度是12em,但因为包装元素还有1em的填充距,所以你得将导航栏盒模型位移13em。你要将它向左移动,也就是说从右边沿移开,这就是为什么我们用的是right属性。

  11. 删掉内容栏的石灰绿背景,这个布局就做好了。

对付IE中出现的奇怪问题

有两个原因会导致这个布局在Windows的IE6中失效。一个是因为IE6不支持min-widthmax-width属性,另一个原因是IS在百分比方面实在是太差了。

你可以用微软的私有标记expression()来模拟宽度约束。该标记以一个JScript表达式作为其自变量,并返回该表达式的返回值。每当浏览器需要获取body的宽度值时都得求解该表达式,因此如果该表达式的运算量很大的话就会导致效率问题。该标记还需要启用JScript,不过你可以添加故障弱化,也就是说,即使JScript不可用,你的设计也可以回落到一个仍然可用的状态。在本例中,如果JScript被禁用的话,你可以将该布局设置为完全弹性,而不是上面创建的那种带约束的可变设计。

建议在样式规则中使用“条件注释”来作为IE浏览器的缺陷补丁。在HTML注释中嵌入条件逻辑(在dev.opera.com上有专门讨论条件注释的文章)是微软独有的特色。

  1. 将下面行插入HTML代码,放在</head>标签之前:

    <!--[if lte IE 6]>
      <link rel="stylesheet" type="text/css" href="layout-ie6.css">
    
    <![endif]-->
  2. 然后,创建一个新文件,加入下面的内容,并将其命名为layout-ie6.css

    body {
      width: 50em;
      width: expression(w=document.documentElement.offsetWidth, em=document.getElementById("nav").offsetWidth/12, (w<40*em?"40em":frown:w>56*em?"56em":"auto")));
    }
    
    #wrapper {
      height: 1em;
    }
    
    #nav {
      margin-left: -22em;
      margin-left: expression((-(document.getElementById("wrapper").clientWidth))+"px");
      left: 13em;
    }

这样就可以解决IE6的两个问题了。我们通过JScript表达式模拟IE6不支持的min-widthmax-width属性,还设置了一个50em的弹性回落值。然后通过另一个JScript表达式将左边距单位设置为像素,而不是百分比,同样也设置了弹性回落值。#wrapper的高度的作用只是触发微软特有的hasLayout,这个属性是保证导航栏元素相对定位的正常运转所必需的。微软在MSDN上提供了hasLayout的文件记录,但这份文档不是轻轻松松就能读懂的。
那么IE7又如何呢?IE7的确支持min-widthmax-width,但它仍然将导航栏元素放错了位置——跟IE6相同的hasLayout漏洞又出现了。你得在#wrapper元素中触发属性。幸运的是,你可以通过一种不损害标准兼容浏览器的方法来解决这个问题,因此可以不必创建单独的IE7样式表;你只需要加入下面的规则来控制包装盒模型就可以了:

#wrapper {
  margin: 0 14em 0 12em;
  padding: 0 1em;
  min-height: 1em;
}

通过对最小高度的设置,触发了hasLayout属性,而且这种做法不会在其它浏览器下引起问题,因此这段代码可以直接添加到主样式表中。

这些解决办法并不是完美无瑕的;在IE6和IE7中,当我们将浏览器窗口的大小调整到某个值时,布局效果还是会产生奇怪的问题,不过只要重新加载一下页面,布局就恢复正常了。

相对定位的其它应用

相对定位的常见用法根本不会牵涉到移动生成的盒模型。这听起来可能有点奇怪:如果不要对盒模型进行移动的话,你干嘛还要使用相对定位?这个问题涉及到绝对定位,因此答案将在下一篇文章中揭晓。别换频道哦!

设置position:relative(不用移动盒模型)对于IE中一些奇怪的渲染漏洞也有用。它可以对内部属性hasLayout进行设置,该属性深刻地影响着IE对页面元素的渲染。

总结

静态定位是元素定位的默认状态。块状盒模型会按照其源顺序纵向排列,而内联盒模型则是在块状盒模型内的线框中横向排列。

使用相对定位,你可以在一个或两个方向上移动某个生成的盒模型。元素仍会像静态时一样占有空间,但生成的盒模型可以被移动到另一个地方。当显示顺序和源顺序不同时,相对定位与浮动联合使用可以有效地创建布局。

posted @ 2009-09-30 11:52    阅读(1678)  评论(0编辑  收藏  举报