[翻译]More Eric Meyer on CSS Pro…

2005-05-22 20:17 | Nautilus

工程1:转换一个现存页面

-看看一个典型的CSS设计师的房间,你看见了什么? 椅子,只有椅子,没有桌子(table)-

—JEAN-YVES STERVINOU

一年又一年....大约...8年吧,当本书仍在写作中的时候,我们在使用表格与占位图片来设计网页的布局,在最开始的几年中,这也是我们作出引人注目的视觉设计的唯一办法.为了迎合对引人注目的设计与布局的渴望,各种工具层出不穷,各个公司也把这种布局方式视为通往精美设计的唯一道路.于是,页面开始越来越臃肿庞大起来.

当CSS出现以后,令页面臃肿化的的趋势改变并让网页变的更小,更有内涵的希望开始浮现.而CSS2出现并提出了自己的页面元素定位法后,在理论上,CSS已经可以在绝大部分地方取代表格并使页面文件尺寸变小.

由于各个浏览器不完全,不兼容的解释与执行,令在各大浏览器上对CSS的实践结果各不相同.虽然对此类问题的改进工作非常缓慢,但是在21世纪到来时,CSS定位布局终于得到了绝大部分浏览器的支持.

想要了解并熟悉CSS定位布局方法的基础,最好的办法是找一张表格定位的页面,把它转换成为CSS定位的.同时,你还可以比较一下,看看在文件结构与大小上有什么不同,也可以看看基本的CSS定位布局可以让你变的多轻松~

工程目标:

我们的目标说的简单点就是:把一张臃肿的完全由HTML标签构成的页面转换成一张CSS驱动的页面.在这个过程中,我们可以看到常见的复杂HTML构成与技巧如何被简单的标签与CSS定义所取代,以及这样得到的页面标签是多么的容易阅读.当我们完成的时候,我们可以选择一些尺度来测试一下,看看我们得到的效果与我们做的让步有什么样的对比.

我们将要评定在文档中遇到的每一个部分,我们完全不知道将要如何处理它们,我们需要明白准确的提出一些目标:

1.文档中的图片数量应当被减少到最少.这样对令文档结构清晰和降低服务器负荷有着极大的作用.
2.所有仅仅是为了布局而出现的表格都应当被去掉,当我们完成的时候,只有那些本来就是用于存放表格数据的表格标签才会仍然存在.
3.我们转换完成后的标签结构应当是健壮的,举例而言,标题内容应当被安置于标题标签内,诸如h1,h2等.更重要的是,即使页面完全的没有了用于表现的标签,内容仍然是被有次序有意义的排放的.
4.最后的完成品应当与它被转换前看起来没什么区别.当然前后不可能相似到连1像素都不差,不过我们应当尽我们所能来减少两者之间的不同.

如果我们可以完成所有的这些目标,那我们就完成了一件意义非凡的事情.

准备:

从http://more.ericmeyeroncss.com下载工程1所需要的文件,并使用你最喜欢的编辑器打开它.

基础

我们需要做的第一件事情是在浏览器中看一下一个完全由HTML构成的页面的表现和它的标签.

图示1:一个完全由HTML标签构成的页面.

现在来看看它的标签代码,不幸的是,我们无法在此提供它的代码,因为如果要把所有的代码都印刷出来的话,那么可能有7页之多.因此我们只有用一个替代方案.

Tip:你可以把工程1所需的文件中的ch101.html在你最喜欢的文字编辑器中打开,这样就可以看到源代码了.

一行一行的分析HTML是枯燥的工作,我们先来个快速浏览吧,看看这个页面是怎么堆砌起来的.我们要临时加一些样式规则到这个文档的头部,那里原本的样式表实在是少的可怜.
<head>

<title>Cleveland Eats: Matsu</title>

<style type="text/css">

body {font-family: Verdana,Arial, Helvetica,sans-serif;}

a.navlink {text-decoration:none;}

/* temporary styles */

table {border: 2px solid red; margin: 2px;}

td {border: 1px dotted purple; padding: 1px;}

/* end temporary styles */

</style>

</head>

新加的规则中,第一条将为所有的表格元素加上2像素宽的边缘与2像素宽的外补白,第2条将为所有的单元格
标签加上1像素宽,紫色的边缘与1像素宽的内补白.这些样式的显示结果就是图示2

图示2:为页面添加临时的简单样式以显示出它的结构

Tip:什么是规则?

CSS规则就是完全的样式定义,它是由选择器和定义框构成. 举例而言,p {color: gray; font-weight: bold;} 就是一条规则

现在红色粗边代表了表格的外部边缘,我们可以很快地弄清楚页面的结构.横跨顶部的BANNER(或者说MASTHEAD)单独放在一个表格中,而其他的内容则是放在另外一些表格中,这些表格又互相嵌套在一起形成了非常复杂难解的结构.有意思的是左边的导航实际上是用2个被放置在不同单元格中的表格构成的,尽管它的效果看起来只是一个方框.

临时加入的这些样式显示出了这个页面所使用的另外一种布局技巧,也就是使用空白单元格来做出空位,举例而言,文字标题与文字内容的两侧都向中间缩进,而不是自然铺开直到页面的边缘(这也就是所谓的缩行引用).你可以看到空白单元格上紫色的虚线边缘.

严格的说,这些单元格里并不是什么都没有,一种特殊的,用来占位的图片位于其中,其文件名一般是spacer.gif,这是一种长宽各1像素的透明图片.对HTML代码进行快速搜索可以知道这里共有18个img标签使用了这种图片文件.当我们的工程完工的时候,它们都将被清除.

转换文档

从一个完全的HTML布局转换到CSS驱动布局需要两个步骤:蜕去基于HTML的表现,然后以CSS控制的样式来取代它.在许多情况下,以一种循序渐进的方式来完成这些工作会比较简单,也就是一个接一个,有顺序地对各个部分进行样式拆分与重建.然而对于这个工程,我们将要彻底地转换并剥离文件内容以使其在开始添加CSS前尽可能的变的最小.

Tip:你可以看到完全剥离HTML样式后的文档,只要把ch0101.html载入你最喜欢的HTML或者文本编辑器就行了.

拆分到最小

现在该备份源文件并除去它所有的HTML样式了.不能否认这是整个工程中最最艰苦的部分,使用查找与替换工具来辅助完成这个工作是个不错的办法,不过最后还需要再对文档进行一次过滤,除去能漏掉的HTML样式.

Tip:清理你的标签
现在有许多工具可以清理表签并把大部分的现有样式除去,HTML Tidy就是这些工具中最流行的,可以在http://tidy.sourceforge.net/免费下载.

你可能会注意到,把文档内容从页面里拷贝出来并为其创建一个新的结构比把旧的结构标签换成新的,更有效的结构标签简单许多.我们将要通过这个转换工程来知道常见的由表格主导的文档标签可以怎样的被简化.必须牢记在内容周围建立新的标签是非常简单的一件事情.

不管你如何缩减标签,必须除去的内容包括以下这些:

1.font 元素
2.<br>元素
3.&nbsp; 实体
4.任何加在body元素上的属性,例如text和link

我们也需要把布局表格彻底除去,但因为原始标签实在太复杂难解了我们必须先弄清楚结构.

文档架构

假定我们已经把前述列表中的所有东西都除掉了,这时,文档的结构仍然很难描述.举例来说,顶部的报头包含一张图片的3个不同切片,每一个切片占据一个单元格.在右上角的另一个单元格则又包含一个表格,导航位于其中.在页面中间的主要位置,左侧的侧边栏被打断成两部分,只是为了一种对齐效果,也就是右边的餐馆名称加上它下面的"底线"文字要与左边的Cuisine: Japanese ,Cost: $$ - $$$ ,Region: East side三行文字在底部对齐,同时令左侧的侧边栏看起来是连续的.这样做的结果是造成了森林般的连锁表格.

上面的那个必须除去内容的列表所列出的内容还可以留上一会,但是我们先尽我们所能除去表格,再看看它们留下的地方,这些完成后,我们就完成了像列表1.1那样的一个文档架构.

Listing 1.1. The Table's Beginning

<table>

[...masthead...]

</table>

<div id="navbar">

[...navbar links...]

</div>

<div id="review">

[...title...]

[..."bottom line"...]

<div id="info">[...sidebar info...]</div>

[...review...]

</div>

Tip:斜体文字.
本书中的斜体文字表示一些太长的内容被省略掉了.

等等,还有一个表格.是的,我们将把那个放置BANNER的表格先留一阵子.我们刚才做的是把这个表格简化同时把导航条挪出来,这时,这个表格的标签变成这样:
<table cellspacing="0" id="masthead">

<tr>

<td><img src="mast1.jpg" alt="Cleveland Eats"></td>

</tr>

<tr>

<td bgcolor="#666666"><img src="mast2.jpg" alt=""></td>

</tr>

<tr>

<td><img src="mast3.jpg" alt="A Guide to Fine Northeast

Ohio Dining"></td>

</tr>

</table>

我们保留这个表格是因为要转换它十分简单,一下子就可以完成.因为中间那个从厨师的盘子底部延伸过来的"有弹性的"表格行是由1像素高的图象切片和单元格背景色完成的.我们可以把它转为无表格结构,并且我们也确实在本工程结尾这样做了.把这个转换放到最后有助于我们理解.
同时,我们来看看导航条吧,没有了单元格,我们需要添加一些东西来把这些超链接分隔开来.我们选择被<b>元素包围的垂直竖线来完成这项工作.

<div id="navbar">

<a

href="/myprofile">my profile</a><b>|</b><a

href="/logout">logout</a><b>|</b><a

href="/top10">top 10</a><b>|</b><a

href="/search">search</a><b>|</b><a

href="contact">contact us</a>

</div>

表格?粗体文字?这真的是一本讲述CSS的书籍吗?是的,耐心些吧,不要忘记,<b>标签是包含在我们所使用的文档格式(HTML 4.01 Transitional)中的,因此使用它是完全合法的.我们不过是小小的向HTML表现让了一下步而已
至于其他的已经被转为骨骼架构的部分,使用<div>元素把它们包围起来.

<div id="review">

<h2>Matsu</h2>

<p id="summary"><strong>Bottom line:</strong>

Friendly, cozy, and oh so tasty</p>

<div id="info">[...all sidebar info...]</div>

[...review text...]

</div>

最后一个无表格转换是把"缩行引用"的部分用定义了类的<blockquote>元素包围.

<blockquote class="pull">

It's so good, it beats out most of the San Francisco-area

sushi places we've tried.

</blockquote>

图示3:现在它被转成了骨骼架构,但是还需要在表现上下些功夫.

重建

由于我们的目标是用CSS重建原有设计布局与内容样式,我们也想研究这个工程剩下的,遍布表格的部分.虽然我们不需要精确重建到像素,但是仍然需要尽我们所能的与原设计相同.首先添加并应用一些基本样式,之后把文档过一遍,为遇到的每一块添加对应的样式.

基本样式

在我们开始全面重建布局之前,先让我们添加一些"全局样式"吧.也就是可以应用到所有文档元素上的样式.首先要把字体大小设置为与原有HTML驱动的文档上的对应文字字体大小相同.设置字体大小时,HTML方式是对大部分文字使用<font size="-2">,而与之最接近的CSS关键字是"x-small".这样,我们把font-family属性换为font属性,并添加一个尺寸值"x-small".

<style type="text/css">

body {font: x-small Verdana, Arial, Helvetica, sans-serif;}

a.navlink {text-decoration: none;}

</style>

Tip:Extra Small
由于原有HTML表现中把字体尺寸值定义为了-2,因此我们使用了x-small这个表现尺寸比medium小两号的关键字.但是IE5对这个关键字的解释有错误,在IE5显示出来的结果接近HTML字体尺寸值-1.IE6修复了这个错误.

我们的一部分转换操作将使body元素摆脱掉诸如leftmargin 或者 topmargin等用于移除环绕于文档内容周围的"装订线"的属性.为了用CSS达到相同效果,我们需要令body元素的内外补白都为0

<style type="text/css">

body {font: x-small Verdana, Arial, Helvetica, sans-serif;

margin: 0; padding: 0;}

a.navlink {text-decoration: none;}

</style>

我们同时定义了内外补白,因为有些浏览器在不定义的情况下默认留出"装订线",其中有的是以内补白形式,而另外一些有的是以外补白形式.对这两个属性都定义可以覆盖所有情况.操作结果见图示4

图示4:添加并应用一些通用样式先

固定头部内容

现在页面的标题部分仍然是一个表格,之前,我们去掉了它的cellpadding 与 width属性,现在则要以CSS重新达成这样的效果.我们假定所有单元格都不需要内补白,同时所有表格的宽度都是100%,如果以后可以不用再管这些,那么就这样假设好了.

body {font: x-small Verdana, Arial, Helvetica, sans-serif;

margin: 0; padding: 0;}

table {width: 100%;}

th, td {padding: 0;}

a.navlink {text-decoration: none;}

现在开始处理导航条.原有文档中,导航条的标签结构是这样:

<td nowrap><font size="-2">&nbsp;<a href="/myprofile"

class="navlink"><font color="#000000">my

profile</font></a>&nbsp;</font></td>

这样的标签防止出现单元格内换行,也使定义字体尺寸的font标签不会被无意义的应用到空格上面,同时定义超链接的字体为黑色.每个超链接还被定义了一个名为navlink的类,规则a.navlink {text-decoration: none;}防止了超链接的下划线的产生.
我们在标签转换的时候除掉了这些类,因为它们是根本不需要的.现在这些超链接被具有属性值为navbar的id属性的<div>标签包围,我们只需要改变规则的选择器来让规则应用到新的位置上.

th, td {padding: 0;}

#navbar a {text-decoration: none;}

</style>

现在我们需要定义连接的颜色并防止它们换行,图示5可以显示我们的进展情况.

图示5:修复报头,开始为导航条添加并应用样式.

放置导航条

现在该把导航条放到它本来应该呆的地方去了,为了完成这个特殊的任务,我们需要为导航条所在的div元素定位.由于这个div元素没有任何上级元素——或者说父元素——曾经被定位过,因此这个div元素就将以这个文档中首个元素的位置为参照来定位,也就是文档最外侧的html元素.

我们知道导航条的位置应该紧靠文档右边的边缘,因此我们需要做的就是测出这个导航条距文档顶端有多少距离.测量像素得到从文档顶端到灰色的分割横线有44像素,因此:

#navbar {position: absolute; top: 44px; right: 0;

white-space: nowrap; background: #F0DFB4;}

现在则要让原有导航条左边的曲线图片回到它该在的位置,在原有文档中,这张图片是放在一个单元格内,用img标签引用的,但是我们在转换标签结构的时候已经把它除掉了,我们可以用把这个图片放到导航条的背景中来重现这个效果.

#navbar {position: absolute; top: 44px; right: 0;

white-space: nowrap;

background: #F0DFB4 url(tab-curve.jpg) bottom left no-repeat;}

你或许会觉得这个点子实在太棒了,直到你发现图片不是在超链接的左边而是再超链接的下面的时候,为了避免图片与超链接的交叠,我们需要一些内补白来解决这个问题(图示6)

#navbar {position: absolute; top: 44px; right: 0;

padding: 0 0 0 32px; white-space: nowrap;

background: #F0DFB4 url(tab-curve.jpg) bottom left no-repeat;}

图示6:为导航条定位并添加一张图片背景.

现在的效果开始向"真TMD的好"转变了,但是文字还是不容易分辨,我们要加一些额外的上,下内补白来让内容垂直铺开.

#navbar {position: absolute; top: 44px; right: 0;

padding: 2px 0 2px 32px; white-space: nowrap;

background: #F0DFB4 url(tab-curve.jpg) bottom left no-repeat;}

我们需要把那些粗体的竖线处理一下下,实际上我们并不希望它们显示出来,对<b>元素使用规则可以轻易地让它们隐形.

#navbar {position: absolute; top: 44px; right: 0;

padding: 2px 0 2px 32px; white-space: nowrap;

background: #F0DFB4 url(tab-curve.jpg) bottom left no-repeat;}

#navbar b {display: none;}

#navbar a {text-decoration: none; color: #000;}

这样处理后,这些文字将不会出现在有样式的文档中,但是如果浏览器没有得到CSS,或者文档是用一个不支持CSS的浏览器查看的,这些文字就会显示出来把超链接分隔开.
这就意味着,在支持CSS的浏览器中,超链接会一个挨一个地排在一起.我们可以使用内补白或者外补白来撑开它们之间的空白.这里我们用内补白(一会就知道为什么.)

#navbar a {text-decoration: none; color: #000;

padding: 0 1em 0 0;}

现在我们需要做的是在导航条的下面加一条边界,这就是需要一些技巧的部分,因为我们不能直接为div元素添加下边界,如果我们这么做的话,导航条的下边界就会超出背景图片的底部而不能对齐,也没有办法让背景图片的底部与导航条的下边界交叠.因此我们把下边界直接加在超链接上.

#navbar a {text-decoration: none; color: #000;

border-bottom: 1px solid gray;

padding: 0 1em 0 0;}

Tip:内联补白
在支持CSS的浏览器中,为超链接添加内补白并不会让包围它们的div的高度增加.这是因为对行元素(比如超链接)增加内补白不会影响到高度的计算,如果内补白足够的话,甚至可以把超链接的边界推出div元素,哪怕是在IE之外的浏览器.

现在,由于div元素在下方有2像素的内补白,添加到超链接上的边界在棕褐色的背景之上1像素,我们需要用一些内补白把它推下来

#navbar a {text-decoration: none; color: #000;

border-bottom: 1px solid gray;

padding: 0 1em 1px 0;}

这样,边界就与背景图片的底部对齐了.如果我们想要把边界向下推以符合原有的设计时,我们只能以1像素,2像素为单位来进行.但是我们的成果就是图示7

图示7:导航条完成了!

为导航条定位的一个极大好处是你可以很容易的移动它,我们可以把导航条放到分隔线的上面而不是下面.基本上,我们只需要计算我们打算放导航条的位置距离顶端有多远以及更换背景图片.这样把导航条放在分隔线上也不过就是小菜一碟.CSS定位也以其弹性成为了引人注目的布局工具.

补白与行元素

增加补白并不会马上就能让超链接伸出包围它们的div元素,因为布局是由CSS决定的,根据CSS的定义,上方和下方的内补白对行高不起任何效果,因此,就算内补白可以被看到,它也不能让文字行高增加,从而,也不能对任何包围它们的元素的高起作用.

但是同时,CSS也规定浏览器不需要处理行元素上下方的内补白.这就可以解释发生在IE/WIN上的一些情况,在这些浏览器上,有些行元素元素的边界与背景不能被显示完全,超出包含它们的元素的边缘的部分被省略掉了.因此,为了达到相同的效果,你会想到为div元素增加内补丁.这个工程剩下的部分会假定这些是不必要的,但是你最好记着,以免以后会遇到这样的麻烦.

使用IE/WIN的读者可以尝试为包围导航条的div元素增加1像素或2像素的内补白,看看是不是看起来更好一点.

标题与摘要的样式

完成报头部分后(至少我们回去除掉表格之前),我们看看评论的开头,这里我们找到了一些很简单的标签.

<h2>Matsu</h2>

<p id="summary"><strong>Bottom Line:</strong>

Friendly, cozy, and oh so tasty</p>

重建标题的外观实在是很简单,只需要取得原有的文字尺寸和文字大小,然后用CSS重新定义以模仿原有样式就行了.

Tip:Extra Large

由于原有文档把标题的尺寸设为+2,我们在这里使用关键字x-large,它比medium关键字代表的尺寸大两号.

#navbar a {text-decoration: none; color: #000;

border-bottom: 1px solid gray;

padding: 0 1em 1px 0;}

#review h2 {color: #600; font-size: x-large;}

</style>

我们也需要在标题上下重新建立空白空间,在原有设计中,这些标题上方的空白是用占位图片做成的,而下方的虚线只是一个包含虚线背景的单元格.我们不再以像素为单位,而是使用以em为单位的属性,先定义了放着,一会再来做调整.

#review h2 {color: #600; font-size: x-large;

margin: 1em 0 0;}

现在来看概要文字,这一短行文字的字体尺寸比起其他的内容文字来要稍大一些,因此我们需要修改字体大小,还有一条虚线把标题和概要文字分开了,因此我们把这条虚线一起插入.目前的进展见图示8

#review h2 {color: #600; font-size: x-large;

margin: 1em 0 0;}

#review #summary {font-size: small; border-top: 1px dotted #600;}

</style>

图示8:标题和概要开始成为焦点

现在出现两个问题,第一个是标题与虚线之间有一个空隙,那是概要文字上方的外补白.另外一个是上方的边缘扩展到了整个文档的宽度,在原有文档中,它是被限制为与概要文字一样宽的

现在我们必须做一个选择:布局成型后,一条横跨文档的边缘似乎不是什么坏事;或者为了最大限度的与原有文档看起来相同,我们来找个办法除去上方的外补白和限制上方边缘让它与概要文字一样宽.

#review #summary {font-size: small; border-top: 1px dotted #600;

display: inline;}

通过这种方法,我们改变了段落元素的布局方式,现在它创建了一个行内盒,就跟超链接元素和span元素一样.段落元素本身仍然是块级元素,但是在屏幕上它创建了一个行内盒,因此边界会与文字的宽度相等,文字变宽边界也变宽,文字变窄边界也变窄.
这种做法有一个缺点,如果概要文字换了行,那么每一行文字的上方都会有一条虚线边界.没有办法能够只为行元素的第一行的上方添加边界,因此如果概要文字有可能换行,那么这就不是一个好的办法.
另外一个缺点是当标题文字比概要文字宽的时候,概要文字不能扩展的足够宽,一个很长的标题配一个很短的下划线是很能说明这个问题的.目前还没有一个比较简单的,让一个元素的宽度能够影响另外一个元素的宽度的办法,除了使用表格.

Tip:行扩展
有一种办法可以让起分割作用的边界的长度与两个使用压缩外补白的元素相同,这样就可以"伪造"上面要求的那种效果.这种技术将在工程8中讨论.

把那些警告牢记在心,我们来看看图示9.我们可以看到在这个例子里关于行元素的应用都工作的非常不错,标题与概要文字之间的空隙也没有了,因为上方与下方的外补白对行元素的布局不起作用.

图示9:让概要文字创建一个行内盒




-

Asimov’s Three Laws of Robotics:



  1. A robot may not injure a human being or, through inaction, allow a human being to come to harm.

  2. A robot must obey orders given to it by human beings except where such orders would conflict with the First Law.

  3. A robot must protect its own existence as long as such protection does not conflict with the First or the Second Law.