上文:
标记语言——打印样式
。Chapter 12 CSS布局本书到此为止,讨论的主要是页面内部元素,也就是内容,但是大结构怎么办?长久以来,设计者都依赖表格进行分栏布局,常常在表格之内嵌套其他表格以便达成恰巧正确的间隔,视觉效果.这些庞大的排版内容不仅下载很慢,维护起来也很费心力,更别提文字浏览器,屏幕阅读器,小屏幕设备根本无法正确读取了.
在这一章内,将使用四种常见的做法,结合CSS于结构化标记语法制作两栏布局.很快地就会发现,不用嵌套表格,间隔用的GIF也能做出分栏版面布局.
稍后在"技巧延伸"中,将会讨论Windows版Internet Explorer 5.0盒模型的问题,以及绕过它的方法.也将分享一个以CSS达成等宽栏位的简单秘密.
#p#要如何以CSS作出两栏版面布局?
答案是有好几种方法,为了带领你起步,同时帮助你了解两种常见方法的差异(浮动与定位),因此先把焦点放在四种不同的方法上,在此每一种方法都能做出两栏布局,同时具备页首和页尾.
我的愿望是:你能以本章作为指引开始构建一个网站,并发挥本书其他章节之内的方法制作内容.
我们将讨论的四种方法都应用在文档的<body>与</body>标签之间,同时我会在开始讨论每种方法之前介绍将会使用的标记语法结构.
为了让你了解围绕着每种方法的页面结构,让我们大致看一下还需要加入些什么:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>CSS Layouts</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
...方法示范...
</body>
</html>
为了让你可以了解要达成的版面配置,请看图12-1:这就是我们想要完成的分栏版面布局.
图12-1 两栏布局的框线图
让我们开始吧!首先介绍第一种方法,它使用float属性.
#p#方法A:浮动侧边栏
div id="header">
...页头部分...
</div>
<div id="sidebar">
...侧边栏部分...
</div>
<div id="content">
...主体部分...
</div>
<div id="footer">
...页脚部分...
</div>
上面就是我们要以CSS的float属性制作成分栏布局的标记源代码,使用<div>标签把页面元素分成几个逻辑段落,每个都设定了唯一的id: #header: 包含标题图片,导航栏等 #sidebar: 包含额外的内容链接与相关资讯 #content: 包含主要的文字内容,也是页面的焦点所在. #footer: 包含版权信息,作者,辅助链接等
把这些页面段落拆开,能让我们能完全控制版面布局,只要指定几条CSS规则,就可以马上完成两栏布局.为页首与页尾指定样式
要把内容结构转化成分栏布局的第一步,是为页首,页尾加上一点背景颜色以及一点内补丁,这样能使内容更容易凸显出来.
#header {
padding: 20px;
background: #ccc;
}
#footer {
padding: 20px;
background: #eee;
}
为方法A的结构加上前面这段CSS会使它显示成图12-2这样,我为各个段落加了一些假象的内容.
图12-2 为页首,页尾指定样式
当然,在#header与#footer里,可以继续为这些段落指定适当的样式,像是font-family,color,链接色彩等等.现在让我们把两栏版面制造出来.浮动侧边栏
方法A的精华,在于它以float属性把#sidebar放到主要内容<div>的任一边去.以这个例子来说,将它放到内容的右侧,但是放到另一侧当然也行.
浮动#sidebar的关键在于,在标记源代码中,必须出现在主内容<div>之前,这样一来,侧边栏的顶部就会与主内容的顶部排齐.
接着,为#sidebar加上float属性,同时把它的宽度设为30%,指定背景颜色:
#header {
padding: 20px;
background: #ccc;
}#sidebar {
float: right;
width: 30%;
background: #999;
}
#footer {
padding: 20px;
background: #eee;
}
图12-3是加上这段CSS之后的显示效果,能看到侧边栏跑到右边去了,而主要内容在侧边栏范围之内流动.
图12-3 把#sidebar浮动到主要内容的右侧真正的栏位
看看图12-3,我们还没有真正完成两栏布局,为了完成这个效果还必须取#content这个<div>,指定与忧侧边栏宽度相同的右外补丁,因此产生放置#sidebar的空间.
需要加上的CSS就是这么简单:
#header {
padding: 20px;
background: #ccc;
}
#sidebar {
float: right;
width: 30%;
background: #999;
}#content {
margin-right: 34%;
}
#footer {
clear: right;
padding: 20px;
background: #eee;
}
我们会发现,我们给content设定的右外补丁大小比#sidebar还大4%,如此能在两栏之间留下一点空位.图12-4是以浏览器查看的效果,你可以发现只要为<div>设定右外补丁,就能造出第二栏的假象.
图12-4 两栏布局
同时要留意的是对#footer所加上的clear:right规则,这个规则很重要,能确保页尾一定会出现在侧边栏和内容区之后,而不受两栏的长度变动影响,页尾会避开任何先前出现的float内容.
现在有了能使用的两栏布局,可以继续为现在的CSS声明加上更多边界,背景,边框与其他元素,使外观更吸引人.
至今为止我们都以百分比设定宽度,以便造出灵活的布局(栏宽会自动随着使用者的视窗宽度缩放).我们也能以像素单位造出定宽布局,但是以像素指定内外补丁大小时,必须注意IE for Windows错误解析CSS盒模型的问题,你能在本章的"盒模型问题"找到更多信息以及能用的解决方法.
#p#方法B:双重浮动
<div id="header">
...header content here...
</div>
<div id="content">
...main content here...
</div>
<div id="sidebar">
...sidebar content here...
</div>
<div id="footer">
...footer content here...
</div>
方法A的缺点之一是:为了浮动侧边栏,则必须在标记源代码之内把侧边栏放到主内容<div>的前面,关闭CSS的浏览器,文字浏览器,屏幕阅读器与其他不支持CSS的设备将会在页面主要内容之前显示(或念出)侧边栏的内容.这样实在不严谨.
我们可以利用float做法,并避开这个问题,只要交换标记源代码里的主内容,侧边栏<div>的位置(如上所示),然后以CSS将两者浮动到不同边即可.
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
float: right;
width: 30%;
background: #999;
}
#footer {
clear: both;
padding: 20px;
background: #eee;
}
通过把两个<div>浮动到不同方向,就能以最恰当的方式排列源代码(主内容放在侧边栏前面),同时仍能得到图12-4这样的效果.避开两边
同样重要的是,你必须将#footerdeclear属性设为both,如此一来不管两栏的长度多长,页尾总是显示在最后,而标签源代码的内容顺序也改善了.
#p#方法C:浮动主内容
<div id="header">
...页头内容...
</div>
<div id="content">
...主内容...
</div>
<div id="sidebar">
...侧边栏...
</div>
<div id="footer">
...页尾内容...
</div>
还有个值得一提的方法,只需要用一个float属性,同时标记源代码仍然可以将主内容的<div>放在侧边栏之前.
只要将主内容的<div>浮动到左侧,并且为它设定小于100%的宽度,如此一来就能在右侧留下足够空间摆放侧边栏.CSS内容
方法C需要的CSS内容再简单不过了,"一个float属性",内容区希望使用的宽度,以及两栏之间留下的小边界.
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
background: #999;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
请注意我们并不需要定义侧边栏的宽度,因为它会自动填满主内容<div>用剩下的空间(在这个例子中是34%).悲惨的背景
图12-5就是以浏览器查看的成果,哦喔!在某些常用浏览器里,侧边栏的背景颜色会出现在主内容区底下,由于侧边栏并未制定宽度,因此它想扩到与浏览器视窗一样宽.
图12-5 浮动内容,但是侧边栏的背景颜色透了出来
这个部分只要我们能在侧边栏左边加上宽度与内容区相同的外边界便可以避开这个问题.实际上我们会把外补丁设的稍微大一点,以便在两栏之间留下一点空白.
简单朴素
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
}
#sidebar {
margin-left: 70%;
background: #999;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
或者是,如果涉及不需要用到背景色的话,那就不必设定边界了,图12-6是去掉整个#sidebar声明,在为主内容<div>加上一点右外补丁之后的结果.此时两栏会共用页面预设的背景色.
图12-6 不使用背景色的浮动内容
CSS则能缩减成:
#header {
padding: 20px;
background: #ccc;
}
#content {
float: left;
width: 66%;
margin-right: 6%;
}
#footer {
clear: left;
padding: 20px;
background: #eee;
}
除了加上左外补丁(或是省去背景色)之外,还有个使用背景图片的替代做法能让分栏具备背景色彩,我稍后会在本章的"技巧延伸 "单元里提示这个小秘密.
除了使用float属性之外,也能用定位制造出分栏布局,让我们看看最后一个选择,方法D.
#p#方法D:定位
<div id="header">
...页首内容...
</div>
<div id="content">
...主内容...
</div>
<div id="sidebar">
...侧边栏...
</div>
<div id="footer">
...页脚内容...
</div>
方法D是使用相同的标记源代码结构,然后以最有效率的方式排列<div>:把主内容放在侧边栏之前,关闭样式的浏览器,屏幕阅读器会先收到主内容部分,再收到侧边栏,在定位时,标记源代码内的顺序与页面元素出现的位置没有关系.能够预测的高度
CSS内容与前三个方法有点类似,第一个差异是对页首指定的像素高度,我们需要能够预测的高度以便稍后为侧边栏定位.
在这里随机选了一个数字,而这需要根据页首使用的内容调整,像是标志,导航栏,搜索表单等.
为各栏留下空间
#header {
height: 40px;
background: #ccc;
}
#footer {
padding: 20px;
background: #eee;
}
接着,要为#content这个<div>设定右外补丁,就像前几个方法一样,这能为右侧边栏留下空间,稍后会使用绝对定位法(不是浮动)把右侧边栏放进去.
放进侧边栏
#header {
height: 40px;
background: #ccc;
}#content {
margin-right: 34%;
}
#footer {
padding: 20px;
background: #eee;
}
最后,要使用绝对定位法把#sidebar这个<div>放到#content的边界里,也必须去掉浏览器在页面周围加上的预设边界,如此一来定位座标在所有浏览器之内就会一致了.
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 34%;
}#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 30%;
background: #999;
}
#footer {
padding: 20px;
background: #eee;
}
在指定position:absolute之后,就能以top与right坐标把#sidebar准确的放到所想的位置(图12-7).
图12-7 以定位做出的两栏布局效果
我们叙述了 "把 #sidebar这个<div>放到距离浏览器视窗上边缘40像素,右边缘0像素的位置",除此之外,也能用bottom和left指定坐标.页尾问题
以先前的方法浮动分栏时,可以用clear属性确保页尾横跨整个浏览器视窗的宽度,而不受主内容,侧边栏的长度影响.
在定位时,侧边栏的文档流独立于整个页面之外,所以只要侧边栏比内容还长,它就会盖住页尾部分.(图12-8)
图12-8 侧边栏与页尾重叠
面对这个问题我常用的解决方法之一,是为页尾指定与主内容一样的右外补丁,让侧边栏能够延伸超过页尾.
使用这个方法的话,CSS需要调整成这样:
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 34%;
}
#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 30%;
background: #999;
}
#footer {
margin-right: 34%;
padding: 20px;
background: #eee;
}
这个解决方案在内容很短,侧边栏很长的页面上看起来有点怪,但是它的确有效,结果可参照图12-9,示范了侧边栏避开页尾的情况.
图12-9 外补丁和主内容相同的页尾
#p#三人行
如果想做三栏布局的话该怎么办?没问题,而且在使用绝对定位时很容易加入.只需要为主内容,也为加上左外补丁,大小足够容纳第三栏即可.
另一个侧边栏能够放在标记源代码之内任何地方,因为会需要再度使用绝对定位进行布局.
假设加了第二个侧栏,并将它取名# sidecolumn,接着以下面这段CSS为它空出位置,再把它放进去.
body {
margin: 0;
padding: 0;
}
#header {
height: 40px;
background: #ccc;
}
#content {
margin-right: 24%;
margin-left: 24%;
}#sidecolumn {
position: absolute;
top: 40px;
left: 0;
width: 20%;
background: #999;
}
#sidebar {
position: absolute;
top: 40px;
right: 0;
width: 20%;
background: #999;
}
#footer {
margin-right: 24%;
margin-left: 24%;
padding: 20px;
background: #eee;
}
刚才完成的部分是在主内容,页尾区空出左外补丁(避免重叠),与之前做右侧边栏一样,接着以绝对定位法放进新的#sidecolumn ,将它放在距离上边缘40像素,距离左边缘0像素的位置.
你有留意我们稍微修正了宽度以容纳第三栏吗?由于我们使用百分比,因此这个布局会随着浏览器的宽度缩放,或者也可以为任何一栏指定像素宽度,以便使布局宽度固定下来.
图12-10是用浏览器查看这个示例的效果,一份以CSS绝对定位完成的灵活三栏布局.
图12-10 以定位法作出的灵活三栏布局
#p#归纳
我们在这章稍微研究了以CSS规划版面布局是能够达成的效果.本章的目的是提供你发挥的基础,因此示范了两种主要的做法: 浮动和定位.
我希望你能继续深入尝试CSS布局技巧,去掉页面内的嵌套表格,并且换上更多浏览器与设备能读取的灵活的结构化的标记语法.
如果你想知道更多关于CSS版面布局的资讯,那么一定要看看这些资源: "The Layout Reservoir" (http://www.bluerobot.com/web/layouts):这是个使用绝对定位制作多栏排版的绝佳示例. "From Table Hacks to CSS Layout: A Web Designers Journey" (http://www.alistapart.com/articles/journey/): Jeffrey Zeldman撰写的绝佳教学,记录了建立双栏布局所需的步骤. "CSS Layout Technoques: For Fun and Profit"(http://www.glish.com/css/): Eric Costello的各种CSS布局资源. "Little Boxes" (http://www.thenoodleincident.com/tutorials/box_lesson/boxes/html): Owen Briggs编写的许多CSS布局示例的漂亮界面. "CSS Zen Garden"(http://www.csszengarden.com/): "示范以CSS为基础的设计能达成什么视觉效果". Dave Shea培养的"花园"以单一XHTML文档展示读者投稿的最新CSS设计(当然也包含布局).这是个能看到CSS布局能力极致的神奇网站. 技巧延伸
现在我们经过了建立基本CSS布局的基础,该是讨论Windows版Internet Explorer 5与5.5版,以及它们错误解析CSS盒模型这个不幸问题的时候了.稍后也会分享一个通过平铺背景图片达成等高栏位布局的秘密技巧.盒模型问题
本章开始的时候我们讨论了建立多栏CSS布局的方法,只用width属性定义每栏的宽度,当你开始为这些栏位加上补丁,边框的时候,事情就变得有些复杂了.为什么?
不幸的是,Internet Explorer 5for Windows在加上内外补丁,边框的时候,无法正确计算外包元素的宽度.
举例来说,除了IE5 for Windows之外,所有支持CSS1的浏览器都会将外包元素的宽度计算为宽度,内补丁,边框三者相加,这是W3C希望所有浏览器处理CSS盒模型的方式.
但是IE5 for Windows会将边框和内补丁算在指定的宽度之内,搞混淆了?不用担心,直接看看问题会对你有所帮助.眼见为实
比较一下图12-11和12-12,图12-11是个200像素宽的元素,两侧各有10像素的内补丁,以及5像素的边框,把水平部分的数值全加起来,就能知道实际宽度为230像素.
图12-11 盒模型的正确计算结果
图12-12 IE5 for Windows 错误的内补丁,边框,宽度计算结果
这是符合设计的盒模型:width属性总是定义元素的内容范围,而内补丁,边框则会加到这个数值上.
因此,如果将侧边栏的宽度定义成200像素然后加上内补丁和边框,CSS的声明如下:
#sidebar {
width: 200px;
padding: 10px;
border: 5px solid black;
}
把宽度设定为200像素,但是侧边栏实际需要230像素的空间,除了IE5 for Windows以外. IE5 for Windows 里侧边栏总共会占用200像素,把内补丁和边框都算在里面.
图12-12 显示的是当width属性指定为200像素时,边框和内补丁会占用内容空间,而不是内容空间之外.
#p#摇摆不定的宽度
我们反对为元素指定边框,内补丁的理由就是实际宽度会随着使用者浏览器的不同而不同,就算在今天,几百万使用IE5.x的用户还是会看到明显偏差的设计结果.同时有个重点必须记住:在这段文字撰写的时候,仍然有太多人在使用IE5以致我们不能忽视这个问题.
所以该怎么办?恩,幸运的是,有个能修复这个问题的技巧,这个技巧可以提供两种不同的宽度,一种给IE5 for Windows,另一种给其他浏览器以便得到正确的盒模型.盒模型Hack
亲切的Tantek Celik写了盒模型Hack (http://www.tantek.com/CSS/Examples/boxmodelhack.html) 让我们能提供两种不同宽度:一种调整过,只会被Window Internet Explorer 5使用,另一种则给其他所有浏览器使用.
通过IE5和IE5.5才有的CSS解析Bugs,可以指定一个略大的宽度(容纳边框和内补丁),然后以实际的宽度覆盖这个数值,让其他浏览器能显示出正确的结果.源代码示例
举例来说,如果希望把侧边栏的内容区域宽度设为200像素宽,加上10像素内补丁和5像素边框,那么我们的CSS看起来就像:
#sidebar {
width: 200px;
padding: 10px;
border: 5px solid black;
}
对IE5 for Windows来说,则需要把宽度指定为230像素(加上两侧内补丁和边框的宽度),接着再以200像素覆盖回来,让符合标准的浏览器得到正确的宽度.
#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for IE5/Win */
voice-family: ""}"";
voice-family: inherit;
width: 200px; /* actual value */
}
留意IE5 for Windows的值先出现,接着几条让IE5 for Windows认为声明已经结束的规则,在此我们使用voice-family属性,原因单纯只是浏览器认得它的话也不会改变视觉效果,最后指定实际的宽度,覆盖最初的width规则,第二个width规则会被IE5 for Windows忽略.
结果在IE5 for Windows以及其他所有兼容CSS2的浏览器上看起来应该完全相同.没有使用这个hack的话,IE5 for Windows的使用者就会看到比设计还瘦的栏宽.对Opera友好
对于同样拥有IE5 for Windows解析错误的CSS2兼容浏览器来说,我们必须在每次使用盒模型补丁之后加上一段额外的声明,这个称为"对Opera友好"的规则会让所有符合标准的浏览器不被解析Bug卡住,确保他们能显示出期望中的宽度.
#sidebar {
padding: 10px;
border: 5px solid black;
width: 230px; /* for IE5/Win */
voice-family: ""}"";
voice-family: inherit;
width: 200px; /* actual value */
}html>body #sidebar {
width: 200px;
}
有了这段规则,就可以完全绕过IE5 for Windows错误解析CSS盒模型的问题,让所有人都能看到正确的效果.
#p#不止宽度
在这里以"盒模型Hack"达成显示相同宽度,但是这个Hack其实能在任何想为IE5 for Windows提供不同CSS内容时派上用场.任何Hack都必须小心使用,同时只有在真正需要的时候才使用,记住 "盒模型Hack"的使用地点是个好主意,这样才能在未来轻易拿掉它.
本文撰写时仍有上百万网络使用者仍然使用IE5 for Windows,因此这个补丁不可或缺.
下面这段"伪装的栏位"原始出自2004年一月份的A List Apart杂志(http://www.alistapart.com/articles/fauxcolumns/).伪装的栏位
关于我个人网站的设计,我最常被问到的问题是:
"你是如何让右栏的背景色一路延伸到整页底部的?"
其实这只是个简单的概念,真的.而且这个概念能应用到本章开始所述的每种布局方法上.垂直伸展
CSS最容易让人感到挫折的性质之一,是元素只会垂直伸展到真正需要的长度.这代表如果在<div>里放一张200像素高的图片,那么<div>就只会在页面上延伸200像素.
当你以<div>切割页面段落,接着用本章开始时的方法用CSS完成多栏布局时,这就会成为有趣的困境,某一栏可能比其他栏都长(图12-13),当你想为每栏选用独特的背景色彩时,视内容多寡而定,做出两个一样长的栏位可能十分困难.
图12-13 长度不一样的栏位
有几个做法能让阑尾看起来一样长,不受栏位包含的内容的影响.我准备分享我的解决方法(适用于绝对定位布局法),而这个方法实在是莫名其妙的...简单.作弊
这个难以启齿的简单秘诀,是用一个垂直排列的背景图片作出彩色栏位的错觉.在SimpleBits(http://www.simplebits.com/),我用了类似图12-14的背景图片(为了示范而修改了比例):左边有装饰用条纹,中间留下宽阔的空白空间安放主要内容,接着是一条1像素的边框,然后是右侧边栏的浅棕色区域,跟着是反向的装饰用条纹.
图12-14 tile.gif 2像素高的背景图片,预先分配好栏宽.
整个图片没有几像素高,但是垂直平铺之后,他就能造成一路到底的彩色栏位,不管栏位内容多长都无所谓.CSS内容
我为<body>标签加上这条CSS规则:
background: #ccc url(tile.gif) repeat-y 50% 0;
这会使整个页面的背景色设为灰色,并且只垂直平铺图片(repeat-y),后面的50% 0代表背景图片的定位:在这个例子里,是从浏览器视窗左边缘算起50%(使图片居中),并且紧贴上边缘.栏位定位
放好背景图之后,在把我的定位布局放到上面,为左栏,右栏指定内外补丁以确保它们会对齐正确位置:也就是背景图创造出来的虚假栏位里(图12-15).
图12-15 平铺背景图创造出的彩色栏位
有个重点必须要注意:如果哪一栏指定了边框,内外补丁的话,就仍然用Tantek Celik的盒模型Hack为IE5 for Windows修正盒模型问题(参照本章稍早的"盒模型问题").
或者是,如果能够只使用外补丁,避免边框与内补丁的话,就不需要加上盒模型Hack了,同时,如果栏位的内容只单纯放在平铺背景图之上(透明显示),那么要避免使用Hack也应该很简单.只要有用就好
虽然我以绝对定位法在自己的网站上做了两栏布局,但是你也能用本章开始时提过的其他方法达成一样好的效果.同样的想法仍然适用:平铺背景图,接着再浮动某个栏位,使其覆盖在模拟的栏位背景上.
这是个简单的概念,但是能够解决设计者在构建CSS布局时经常遇到的挫折之一.结论
我希望本章能带给你开始探索CSS布局的刺激世界,本章开始时我们看到了四种构建版面布局的方式,其中三种用了float属性,还有一种用了绝对定位.一定要去看看我列出的额外资源,里面有更多布局的技巧和示范.
我们也讨论了盒模型Hack在建立具备边框,内补丁的栏位时有何重要性,让这些效果在IE5 for Windows以及其他浏览器上表现一致.
最后,我分享了一个有用的技巧,让你在设计CSS布局时能做出等高栏位,这是某些人认为十分基本,但实现上经常让人感到挫折的设计目标.只要小小一个平铺背景图就能搞定,让你得到能够抵达页面底部(不管内容多长)的栏位.
个人比较习惯用多次浮动来布局,这方面随个人喜好了,没必要强迫使用哪一种布局方法,就算你用table来布局,你认为爽也不会有人说什么...哈哈,玩笑