利用负值的外补丁创建液态布局

Creating Liquid Layouts with Negative Margins

  我最近面对的一个任务要求创建一种包括页头(header)和页脚(footer)的两栏液态布局(two-column liquid layout),同时要保证源代码中内容(content)部分出现在侧边栏(sidebar)之前。利用这次机会,我充分利用了一个CSS中被遗忘的角落:负值外补丁(nagetive margins)。负值外补丁充许我们将内容部分从浏览器的一边推开,以便给侧边栏留出一个位置。

由简入手

  为了说明负值外补丁是如何帮助我们创建液态布局的,我们先创建一个包括了页头和页脚的两栏液态布局开始。主内容区域将出现在页面的左侧,而侧边栏出现在右侧。一般情况下这是一个相当简单的任务,但是我们的情况有一点不同,因为我们的原代码是按一种特定的方式结构化了的(译者注:即内容部分出现在侧边按之前,下文将表明这样做的好处)。

  根据float规则的执行情况,最简单的方法是(在源代码中)将侧边栏放在内容区域之前,并且让它浮动到右边由内容部分空出来的区域中。然而,更好的选择是在文本浏览器、屏幕阅读器和一些不能显示样式表的古董级的浏览器中让页面内容出现在侧边栏之前,并且能够在主要的浏览器中正常地工作。

我们需要的源代码

  让我们来看一下XHTML源代码应该长得什么样:

<div id="header">header</div>

<div id="container">
  <h1>content</h1>
  <p>Lorem ipsum dolor sit amet,
  consectetuer adipiscing elit.
  Phasellus varius eleifend.</p>
  <p class="last">Donec euismod.
  Praesent mauris mi, adipiscing non,
  mollis eget, adipiscing ac, erat.
  Integer nonummy mauris sit.</p>
</div>

<div id="sidebar">
  <h1>sidebar</h1>
  <ul>
    <li>link one</li>
    <li>link two</li>
  </ul>
</div>

<div id="footer">footer</div>

  查看例1,看看没有样式表的文档表现如何。看到这个你就明白为什么我们要把内容放在侧边栏目之前,在不支持CSS的浏览器中看起来就是这个样子的。

  内容部分的宽度应该是整个可用的宽度减去侧边栏的宽度(译者注:即液态的意思,内容的宽度随着浏览器的改变而改变)。想想如果我们可以设定宽度为100% - 200px会怎么样?用负值外补丁就能实现这个效果。千真万确!

我们将要用到的CSS

  为了实现这个效果我们要解决CSS的问题。首先把container div的宽设置为100%,向左浮动,并把它的右外补丁设置为-200px。 浮动这个元素是很重要的,因为对浮动并且内联元素的外补丁(包括这里的负值外补丁)的处理与对非浮动的块级元素的处理是不同的。

  除了让侧边栏浮动到这个元素(译者注:指container div)内的右侧区域,设置负值右外补丁比设置为正值能做更多的事,我们将在例2中看到这一点。接下来把侧边栏浮动到右边并且把宽度设置为200px。最后,我们给页脚增加一条样式规则:“clear:both;”,保证它可以正确地呆在其它内容的下方,无论两个竖栏的哪个更长一些。同时我们也给页头和页脚设置背景颜色,把它们与页面的其它部分区分开来。

#header {
  background: #d7dabd;
}
#container {
  width: 100%;
  float: left;
  margin-right: -200px;
}
#sidebar {
  width: 200px;
  float: right;
}
#footer {
  background: #d7dabd;
  clear: both; 
}

  这个CSS将产生如例2所示的结果。你一定发现了现在需要做的是把内容区域的右边界从页面的右边向左边拉过来一些。我们采用了增加一个div嵌套的方法,这样做比其它的一些备选方案拥有更好的浏览器支持。

<div id="container">
  <div id="content">
    <h1>content</h1>
    <p>Lorem ipsum dolor sit amet,
    consectetuer adipiscing elit.
    Phasellus varius eleifend.</p>
    <p class="last">Donec euismod.
    Praesent mauris mi, adipiscing non,
    mollis eget, adipiscing ac, erat.
    Integer nonummy mauris sit.</p>
  </div>
</div>

  我们给新增加的这个div设置一个右外补丁和背景颜色,使它被正确地放置在它应该在的地方并且和侧边栏分开来。

#content {
  background: #f1f2ea;
  margin-right: 200px;
}

解决一些问题

  我们往前跳过一些可视的例子,先来修正另一个问题。content div中的第一个元素不能有上外补丁(top margin)而最后一个元素不能有下外补丁(bottom margin)。在我们的这个案例中,只需要简单地把h1的上外补丁设为零,同时给content div中的最后一个段落(p)设置一个class,在这个class中设置下外补丁为零。做完这些我们就可以来看看例3了。

  这回好一些了,但同时你也一定注意到了右侧边栏并没有正确地扩展到底部。感谢一个使用背景图的窍门,我们可以用它来修正这个问题(参见Dan Cederholm发表的“Faux Columns”)。

  首先,与侧边栏的宽度相对应,我们创建如下宽度为200px的图像。

the image we'll use to create the faux-column background

  为了实现Dan的窍门,我们在container和sidebar的外面再加上一个wrapper div,同时在它们的下面增加一个含有规则clear:both的div。现在我们的XHTML看起来应该是这个样子的。

<div id="wrapper">
  <div id="container">
    <div id="content">
      <h1>content</h1>
      <p>Lorem ipsum dolor sit amet,
      consectetuer adipiscing elit.
      Phasellus varius eleifend.</p>
      <p class="last">Donec euismod.
      Praesent mauris mi, adipiscing non,
      mollis eget, adipiscing ac, erat.
      Integer nonummy mauris sit.</p>
    </div>
  </div>
	
  <div id="sidebar">
    <h1>sidebar</h1>
    <ul>
      <li>link one</li>
      <li>link two</li>
    </ul>
  </div>
  <div class="clearing">&nbsp;</div>
</div>

  现在我们再把背景图加到wrapper div中:右侧纵向平铺。为了修正Internet Explorer的一个bug,还需要在container div中也加入相同的背景。

#wrapper {
  background:
    #f1f2ea url(background.gif) repeat-y right;
}
#container {
  width: 100%;
  background:
    #f1f2ea url(background.gif) repeat-y right;
  float: left;
  margin-right: -200px;
}

  我们还需要设置clearing div的样式以保正页脚处在两个竖栏(container和sidebar)的下方,这样显示才会正确。(译者注:这种clearing div的方式在IE中有一些小小的bug,请参看译者发表的另一篇文章,可以比较完美地解决这个问题。)

.clearing {
  height: 0;
  clear: both;
}

  这样我们就得到了一个美观的两栏液态布局,在没有CSS情况下它也表现良好。看看例4。再简单地加入一些边框和内补丁你就可以开始构建一个很棒的两栏液态布局。当然,如果我们想要侧边栏出现在布局的左侧(译者注:原文为右侧,疑为作者笔误),只需要把浮动元素和外补丁设为反向设置即可。看到float: left,就把它改成float: right;看到margin-right: 200px,请改成margin-left: 200px,等等。

更多的窍门:三栏液态布局

  我们把上面的结果再改进一下,以便实现一个液态内容区域的三栏布局(译者注:即左右两栏固定,中间一栏的宽度随屏幕的改变而改变)。我们不仅能做到这一点,而且出人意料的简单。首先需要对XHTML做一些“最终”的改变:增加几个div,接下去再修改一下CSS。

<div id="outer_wrapper">

  <div id="wrapper">
    <div id="container">
      <div id="content">
      
        <div id="left">
          <h1>navbar</h1>
          <ul>
            <li>link one</li>
            <li>link two</li>
          </ul>
        </div>
        
        <div id="main">
          <h1>content</h1>
          <p>Lorem ipsum dolor sit amet,
          consectetuer adipiscing elit.
          Phasellus varius eleifend.</p>
          <p class="last">Donec euismod.
          Praesent mauris mi, adipiscing non,
          mollis eget, adipiscing ac, erat.
          Integer nonummy mauris sit.</p>
        </div>
        
      </div>
    </div>
		
    <div id="sidebar">
      <h1>sidebar</h1>
      <p>Here be your sidebar.
      Add whatever content you may desire.</p>
    </div>
		
    <div class="clearing">&nbsp;</div>
  </div>
  
</div>

重新实现Faux栏(faux columns)

  我们希望页面上所有的竖栏看上去都一样高,这就需要再创建几个Faux栏。为此我们先创建如下两个图像。

 

the images we'll use to create faux-column backgrounds

  从上面的XHTML中可以看到,我们在最外面又裹上一层div,同时把中间的内容部分也裹在一个新的div中。新的div中将含有新的左侧纵向平铺至div底部的背景。然后把content div的背景去掉,把想要的背景色加到outer_wrapper上。

#outer_wrapper {
  background: #fff url(background_3.gif) repeat-y left;
}
#wrapper {
  background: url(background_2.gif) repeat-y right;
}

  背景图不显示的地方将显示出白色的背景色,正好给中间的一栏(content)着色。我们还要给内部元素增加背景图以防在IE的大多数版本中出现难看的缝隙。

#container {
  width: 100%;
  float: left;
  margin-right: -200px;
  background: url(background_2.gif) repeat-y right;
}
#content {
  margin-right: 200px;
  background: url(background_3.gif) repeat-y left;
}

  接下来再加上一此简单的样式,用外补丁使左侧竖栏和中间的竖栏正确定位到我们期望的位置。

#main {
  margin-left: 150px;
}
#left {
  width: 150px;
  float: left;
}

  最后,我们把下面的样式加到页头和页脚div上,使它们看起来比较像那么回事。

border: 1px solid #cecea5;

  看看例5,你可以轻松地看到整个源代码。

  当然,在你最终的站点里采用@import规则会是个好注意,这样能让我们的页面在那些老古董浏览器里显示得好一些。

结论

  如你所见,负值外补丁这个CSS中被遗忘的角落对于那些想要控制元素在源代码中出现的顺序并且不太介意加入一个无语义的包裹div的人来说是极有用的。

Translated with the permission of A List Apart Magazine and the author.
A List Apart杂志和原作者的授权下翻译。

雅虎收藏