More Eric Meyer On CSS 工程2

2005-06-17 16:23 | ovelia

工程2. 给一个图片集添加样式

一切照片的存在都是为了让我们回忆起那些我们忘却了的事情。在这种意义上——正如在其他意义上一样——它们和绘画是截然相反的。绘画记录下来的是画家的记忆。而因为我们每一个人忘却的都是不同的事情,因此正是照片,而不是绘画的含义,能够随着观看者的变化而变化。-- John Berger

尽管不是每个人都会把他或者她的照片放上网,对这样的相册的设计依然是一个有趣的挑战。每张照片及其相关联的信息构成了一个小而完整的单元,而这些单元在排版的时候是需要考虑到它们之间的关系的。在某种意义上它们和门户网站一样,只不过这里的每一个方框并不是导向最新消息或者比赛情况的页面,而是一个导向一个图片信息的页面。

相册这个题目也和另外一种更为普遍的设计模式颇为相像:就是在不少电子商务站点上都会出现的商品目录。的确在某些时候,这些图片可能就是销售的商品,这也是我们现在这个工程的一个假设。

工程目的

在这个工程中,我们需要寻找一些方法来展示我们要出售的照片。我们客户的要求如下:

一共需要三种不同的图示:一种是“联系表格”,提供给艺术家查询现有可以出售得自己的图片,另外一种是“画廊”,让用户能够看到全部的货物清单,最后一种是“目录”,是在订购的时候使用的。

再画廊和目录模式下,页面需要在避免因为浏览器窗口大小变动而出现水平滚动条的情况下,将尽可能多的图片显示出来。在这两种模式下可以只需要显示图片及其名称,另外图片应该排列成一个矩阵;而在目录模式下,每张图片都需要显示其标题,编号以及价格。滚动条的出现是允许的。

在三种模式下对于页面的内容应该使用同样的HTML标记,因为我们的客户并不想制作一个动态的网站,因此希望页面的HTML标记能够只生成一次。

在这个工程中我们只需要对图片集进行样式设计,我们并不需要担心别的问题。我们可以假定这个样式能够成为一个主站的其中一部分,不过那不会改变我们这个工程的性质。

由于工程本身,特别是在画廊和联系表格模式的限制,我们将不能使用表格来对这些图片进行排版。为什么?因为我们得到的要求是在直接显示范围内(注:原文“above the fold”为术语,指浏览器窗口在不拉动滚动条的情况下能显示的范围)要显示尽可能多的照片。因此,我们将采用CSS的float在这两种“紧凑”模式下来排列图片。使用float能使我们每行得到尽可能多的照片,在800*600的浏览器窗口下是每行4张照片,而在1280*1024的窗口下是6到7张。使用float可以轻松造出这种“流动”的行为,而这是表格没法做到的。另外作为附加的效果,我们可以设置每个图片单元的float属性,使得它们的宽度一致,这样就能保证它们能排成一个类似表格的效果。

准备

从http://more.ericmeyeroncss.com下载工程2所需要的文件。其中ch02proj.html是我们最原始的页面文件,你可以用你选择的任何一款编辑器来进行编辑。

打好基础

我们要做的第一件事是看看我们要添加样式的一些HTML标记。这里是开头的两张图片以及信息的标记:

<div class="pic ls"><a href="orig/img01.jpg" class="tn"><img

src="tn/thumb01.jpg" alt=""></a><ul>

<li class="title">The Ferrett's Daffodil</li>

<li class="catno">03F01</li>

<li class="price">$79.95</li>

</ul></div>

<div class="pic pt"><a href="orig/img02.jpg" class="tn"><img

src="tn/thumb02.jpg" alt=""></a><ul>

<li class="title">At Lunch</li>

<li class="catno">03F02</li>

<li class="price">$59.95</li>

</ul></div>

空白字符的忧郁

仔细观察一下标记:需要注意的是,ul的开始标记贴在超链接的后面,</div>也贴在了</ul>的后面而没有换行。这是为了避免在老版本的IE里面出现多余的空白字符。这是挺不幸的,不过对于某些老版本的浏览器来说,空白字符还是很受重视的,因此某些时候加上或者去掉空白字符能够解决某些神秘的排版问题。

恩,这里已经有很多个类了,我们需要找到他们各自的含义。幸好我们这里有一个指引。

  • pic 标记的是所有包含了图片及其关联信息的div,因此这个pic应该是用来使这些div能够分隔开来的。
  • ls 表示这张图片是风景图(即高度大于宽度),而pt则表示图片是肖像图(宽度大于高度)。
  • tn 表示这是图片所代表的链接。
  • title表示图片标题,catno编号,price么……这不是很明显么。

我们将要看到的是,在这里面真正重要的类是ls和pt,不过他们都是挺有用的。举个例子,在设置图片的高和宽的时候,我们就会用到这些类了。正如你所看见的那样,我们并不会用HTML来表示这些属性。我们当然知道风景图的分辨率一律为128*96,肖像图则是96*128,但是我们必须在CSS里面声明这些属性。

作为工程的开始,我们先加上一些基本的body和footer(脚注)的属性,对于body标记我们只需要加一个淡色调的背景以及边框的属性。我们知道接下来要经常用到float,因此我们需要让脚注放在图片的后面,在这里我们会用到clear属性。图2.1显示了以下这些属性设置的效果。

<style type="text/css">

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

</style>

图2.1. 最开始的一步。

这些属性会一直用到最后,所以我们不需要再理会它们了。下面我们开始正事吧 ^^

创建联系表格视图

在这一步,我们已经能看清楚文档的结构了:图片以及ul标记。我们要做的是“联系表格”样式的建造,在其中图片要排成一个类似表格的形式。这样可以一次性看到尽可能多的图片。

漂浮的图片

由于我们不会使用表格,很明显我们应该用float属性。我们知道图片的高和宽都不可能超过128,因此我们给div定下了128*128的大小,还给它们一个白色的背景和黑色的边框。说到边框么……我们还要把图片链接周围的蓝色边框给去掉。

边框事故

当然不是所有的浏览器都会给图片链接加上边框,但是有些浏览器是会的,因此显式地把边框去掉还是有必要的,这并不会影响那些不给图片链接加上边框的浏览器。

div#footer {clear: both; padding-top: 3em; font: 85% Verdana, sans-serif;}

div.pic {float: left; height: 128px; width: 128px; background: white; border: 1px solid black;}

div.pic img {border: none;}

</style>

图 2.2. 给div加上float属性之后的效果。

我们已经向我们的目标跨过了一大步了,但是这里有一个很明显的问题——列表!因为我们显式声明了div的高宽,所以列表就没有空间容下了,因此他们都掉到了div的范围之外,弄得我们地排版乱糟糟的,因此我们现在就必须把它们都去掉。

对IE的观察

在windows下的IE,列表会把div的高度撑大,而不是直接溢出去,不过效果也一样很难看。这是因为IE 5+的一个bug,把height当成是min-height了(但是min-height IE却不支持,真讽刺……)

div.pic img {border: none;}div.pic ul {display: none;}

</style>

现在那些信息就不会被显示了。我会在将来改变样式的时候还会用到这些列表的,不过现在我们就可以直接不显示它们了。

留间距与居中

由于float,我们现在的图片已经排成一个类似表格的形式了,不过感觉有点挤?不用急,我们给div加一点margin让他们分开。

div.pic {float: left; height: 128px; width: 128px; margin: 5px 3px; background: white; border: 1px solid black;}

由于各个漂浮之间的边界是不会折叠的,所以两个漂浮的div之间的横向距离是6个像素(3px + 3px),纵向则是10个像素。当然这个是可以根据自己的喜好来调整的。我们现在的效果如图2.3所示。

图2.3 用margin把所略图分开之后的效果。

现在是不是越来越好看了呢?^^ 不过图片现在看来还是比较怪的,贴着方框的左边缘或者上边缘。如果给它们居中的话那会好看多了。我们首先要给图片定一个尺寸。

div.pic img {border: none;}div.ls img {height: 96px; width: 128px;}div.pt img {height: 128px; width: 96px;}

div.pic ul {display: none;}

我们在这里只是表达了我们所知道然而浏览器并不知道的事实:就是风景图(ls)都是128*96而肖像图(pt)是96*128的。还记得我们给div定义的128*128的高宽么?因此我们只需要给图片留点边缘就行了。而这点边缘的宽度(或者高度)是(128-96) / 2 = 16,因此我们只需要给风景图留16像素的上边缘和下边缘,而给肖像图留16像素的左右边缘。这时候的效果如图2.4所示。

div.ls img {height: 96px; width: 128px; margin: 16px 0;}

div.pt img {height: 128px; width: 96px; margin: 0 16px;}

图 2.4. 给缩略图居中之后的效果。

幻灯片般的图片样式

这已经是个不错的效果了,不过我们还可以做得更好些,我们可以给div加一些补白,使得缩略图的周围都用白色的框围住,我们添加的是16像素的补白,为什么是16?因为我们一直在用2的N次方呀(笑)。

div.pic {float: left; height: 128px; width: 128px; padding: 16px; margin: 5px 3px; background: white; border: 1px solid black;}

到这里已经越来越像一个35mm幻灯片的集合了,我们就依照这个思路继续吧。首先我们给图片加上一个照片嵌入效果的边框。

另一种做法

除了下面要展示的方法之外,我们还可以用单色的边框 + 边框样式 inset,不过这种方法有一个缺陷:因为浏览器是可以自由设定inset(以及outset, groove, ridge)的样式的。所以可以预见的是不同的浏览器做法都会不一样。因此由于这个边框生成的阴影效果很重要,所以还是用solid加上自定义的颜色比较好。

div.pic img {border: 1px solid; border-color: #444 #AAA #AAA #444;}

这一条改动使得所有的图片都有了一个暗灰色的左/上边框以及一个亮灰色的右/下边框,这种嵌入效果已经很不错了。不过这个规则也有它的短处:图片加上它们的边框已经超出了128*86的大小,现在他们是130*98,所以我们必须改动关于高度和宽度的设置以及补白。

div.pic {float: left; height: 130px; width: 130px; padding: 15px; margin: 5px 3px; background: white; border: 1px solid black;}

有了这些细微的改动之后,我们终于又恢复到平衡状态了。作为幻灯片效果的最后一步,让我们给div的边界制造一种凸出的效果吧。我们用到的颜色和刚才用于嵌入效果的是一样的,只不过上下左右的位置变反了而已。

div.pic {float: left; height: 130px; width: 130px; padding: 15px; margin: 5px 3px; background: white; border: 1px solid; border-color: #AAA #444 #444 #AAA;}

你现在应该发现,我们把border属性里面的black去掉了。毕竟有了border-color,我们就不需要这个属性了。去除这个属性也可以节省文件大小。现在的结果如图2.5所示。

图 2.5 一个类似幻灯片列表的东西...

是不是已经很像35mm的幻灯片了呢?且慢,我们还能做得更逼真呢。我们与其依赖于背景色和边框,还不如使用更为逼真的背景图片作为像框。

如何做到呢?我们已经知道了,整个div包括边缘的大小是162*162,算法是这样的(用风景图的宽度为例):

128px 图片宽度 + 2px 图片边框 + 30px div的补白 + 2px div的边框 = 一共162px

由于我们要把div的边框给去掉,所以可以不算在内,那么就是一共160*160。所以我们的背景图的大小也应该是160*160。因为我们有两种图片大小,所以也需要两种背景。我们给它们取名为 frame-pt.gif 和 frame-ls.gif。不管我们是用扫描仪还是用Photoshop做出这种类似像框的效果都不紧要,我们有这两个背景就行了 ^^ 现成的两个gif图片可以在本书的配套网站上找到。

当我们弄好了背景图之后我们只需要在样式表里加上背景图的设置就好了。当然我们还需要把原有的边框样式给去掉。

div.pic {float: left; height: 130px; width: 130px; padding: 15px; margin: 5px 3px; background: url(frame-ls.gif) center no-repeat;}

不过这样的话那些肖像图就很难看了,因为这个不是给它们用的像框。所以我们需要在pt这个类下面覆盖上层的背景属性。

div.pic {float: left; height: 130px; width: 130px; padding: 15px; margin: 5px 3px; background: url(frame-ls.gif) center no-repeat;}

div.pt {background-image: url(frame-pt.gif);}

div.pic img {border: 1px solid; border-color: #444 #AAA #AAA #444;}

这样的覆盖效果是,只有背景图片的属性被覆盖了,而center no-repeat并没有被覆盖,所以url(frame-pt.gif);的效果就等于是 url(frame-pt.gif) center no-repeat了。效果如图2.6。

图2.6 现在终于看上去像是一堆幻灯片的集合了吧,呵呵。

现在的效果挺好的是不?一个好消息是你可以用自己喜爱的背景图来替换现有的“像框”了。列表2.1显示了目前新添的所有样式。现在请将目前的文件另存一份,因为下一部分会对这部分的内容进行删改的。

列表 2.1. 完整的“幻灯片效果”样式表

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em; font: 85% Verdana, sans-serif;}

div.pic {float: left; height: 130px; width: 130px; padding: 15px; margin: 5px 3px; background: url(frame-ls.gif) center no-repeat;}

div.pt {background-image: url(frame-pt.gif);}

div.pic img {border: 1px solid; border-color: #444 #AAA #AAA #444;}

div.ls img {height: 96px; width: 128px; margin: 16px 0;}

div.pt img {height: 128px; width: 96px; margin: 0 16px;}

div.pic ul {display: none;}

创建画廊模式视图

尽管前面的样式表让人很感兴趣,这个视图并不会显示图片的名称,这就很成问题了。尽管对于艺术家本人这是一个很好的展示图片的模式,毕竟他是知道哪张图片叫什么名字,因此排版要比较简洁一些。而对于参观者而言,需要的是实用,而这种样式并不能让人满意。因此我们得把幻灯片样式改成一个图片的画廊,每一张图片都用它的题目作为标题。

去除幻灯片样式

首先我们得把原先的幻灯片样式的规则去掉(看图2.7),余下的样式表如列表2.2所示。

列表2.2 精简过后的样式表

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

div.pic {float: left; height: 130px; width: 130px;

padding: 15px; margin: 5px 3px;}

div.pic img {border: 1px solid; border-color: #444 #AAA #AAA #444;}

div.ls img {height: 96px; width: 128px; margin: 16px 0;}

div.pt img {height: 128px; width: 96px; margin: 0 16px;}

div.pic ul {display: none;}

图2.7 去除幻灯片样式后的样子。

我们距离我们的目标其实已经很接近了,不过现在我们首先要把标题显示出来。

显示标题

为了显示标题,我们要解除ul的隐藏属性,然后把我们现在不想看到的部分隐藏掉。解除隐藏其实很简单:我们把div.pic ul属性的display: none; 去掉即可。

div.pic ul {}

声明一下,大括号内不写任何属性的做法是合法的,虽然这样没什么作用,因为没有任何属性会应用到这个标记上。下面我们就来填这个空。首先我们给ul设定补白和边缘属性,以及字体的样式。

div.pic ul {margin: 0.25em 0 0; padding: 0;

font: bold small Arial, Verdana, sans-serif;}

现在这些列表能够看到了^^ 不过,我们只需要让它们的标题出现而已,所以我们需要隐藏其他的列表项(编号和售价等),如图2.8所示。

div.pic ul {margin: 0.25em 0 0; padding: 0;

font: bold small Arial, Verdana, sans-serif;}

li.catno, li.price {display: none;}

</style>

图2.8 显示标题的同时隐藏其他项

恩,现在不错了,不过很明显我们还可以做得更好些。首先我们要把标题前面的那个点去掉,因为它们只会让人分心而且很难看-,- 用list-style是可以的,不过我们也可以只需要改变li的属性,使得li不再是一个列表项(display: block;)。这样在其他的浏览器中能够很好地显示,不过在Windows下的IE依然会出现那个点,所以还需要用list-style补救一下,这样就能兼顾兼容性了。最后我们需要把文字居中。

div.pic ul {margin: 0.25em 0 0; padding: 0;

font: bold small Arial, Verdana, sans-serif;}

li.title {display: block; list-style: none; text-align: center;}

li.catno, li.price {display: none;}

现在我们要让标题更靠近那些图片。如果你还记得的话,我们在上一节,创建幻灯片样式的时候给图片添加了边缘。正是这些边缘使得某些风景图的图片与标题之间隔得太开。

记住我说的是风景图而不是肖像图,因为肖像图并没有设置上下边缘。因此我们只需要对风景图的边缘进行改动。另外留意一下图2.8中一个有意思的地方:每一行图片的所有标题的第一行文字都是在同一条直线上的。这个效果是值得保留下来的,因此与其直接把风景图的下边缘去掉,还不如把所有的边缘像素(32px)都移到上边缘。

div.ls img {height: 96px; width: 128px; margin: 32px 0 0;}

到现在为止都很顺利,不过有些问题我们还没考虑到,那就是div的高度。它们依然是130px高,加上一些补白。也就是说,那些标题实际上有掉出所在的div的危险。如果我们给div加一个调试用的边框的话,我们就能看见问题的所在了,如图2.9所示。

图2.9 快完成了,不过好像超出了……

对IE的观察

像以前一样,windows的IE的一个高度bug会使IE的显示效果不同于2.9所示的那样。

div.pic {float: left; height: 130px; width: 130px;

padding: 15px; margin: 5px 3px; border: 1px dotted silver;}

清理

到了这个阶段,我们需要做的只剩下把div加高,使得有空间让文字能够放进div里面去。如果我们不放进去的话,在IE里面整个排版就会乱掉。另外一个理由是,如果在一个超长的标题下面恰好又是一张肖像图,那么两者叠在一起的机会是非常高的。第三个理由,仅仅是让一个元素超出它的父元素的范围这个idea本身就非常的不合理(当然只是现在会这样;在工程的下一步我们还要用到这个idea的优点呢)

所以我们把div上下的补白都去掉,然后增加div的高度到190px。另外把刚才加上的临时边框给去掉。

div.pic {float: left; height: 190px; width: 130px;

padding: 0 15px; margin: 5px 3px;}

现在我们终于做好画廊视图了^^ 样式表见列表2.3,效果见图2.10。

图2.10 赏心悦目的花园画廊

现在是分开另存一个文件的好时机了,因为下一部份的工程将会把现有的大部分成果都抛弃掉。

列表2.3 画廊视图的样式表

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

div.pic {float: left; height: 190px; width: 130px;

padding: 0 15px; margin: 5px 3px;}

div.pic img {border: 1px solid; border-color: #444 #AAA #AAA #444;}

div.ls img {height: 96px; width: 128px; margin: 32px 0 0;}

div.pt img {height: 128px; width: 96px; margin: 0 16px;}

div.pic ul {margin: 0.25em 0 0; padding: 0;

font: bold small Arial, Verdana, sans-serif;}

li.title {display: block; text-align: center;}

li.catno, li.price {display: none;}

高度与表格

现在的情况下,只要标题不超过3行,那么选择190px的div高度是明智的,因为这样不会溢出。但是如果标题超过3行达到5-6行呢?这样的话整个样式就会坏掉了,而且没有办法修理这个问题。

这是漂浮元素的一个固有的缺陷。效果上来看,每个漂浮元素本身都是一个孤岛:它和其他的元素完全可以重叠在一起。换一种说法的话,在网页设计中只有表格单元会自动设定自己的大小,来符合它们的邻接元素的位置。

这就意味着在某些时候,表格对于画廊模式来说是最好的选择。如果有这么一种情况,图片的标题长度是不可预知的,或者你只是想让每张图片占据一个空间,高度和同列中最高的那个是一样的话,那么你就必须使用表格了。当然你也可以采用我们现在所探索出来的一些CSS技巧来润饰你的表格内容。

另外一个必须使用表格的情形是,如果你希望让你每一行的图片数量固定下来的话。当然用CSS和一点小技巧也可以做到这一点。例如下面这种形式的文档组织:

<div class="row">

<div class="pic ls">...</div>

<div class="pic pt">...</div>

<div class="pic ls">...</div>

<div class="pic ls">...</div>

</div>

无表格的表格排版!

这种形式的确就是一种漂浮和表格之间的折中解决办法:用在这里显示的标记,然后给这些标记加上表格显示所需要的参数即可。例如我们可以声明一个 div.row { display: table-row;} 还有 div.row div {display: table-cell;} 这样创造出来一种类似表格的效果,但是却不需要用到表格,而且在目前除IE以外(这是当然了-,-)的浏览器上都能正确地显示。

就这样,我们给每4张图片分一个组,我们就可以让每一行永远只显示4张图片了。不过为什么我们能够用表格的时候却不去用呢?我们刚才使用的标记和下面的表格标记实际上结果是一样的:

<tr>

<td class="pic ls">...</td>

<td class="pic pt">...</td>

<td class="pic ls">...</td>

<td class="pic ls">...</td>

</tr>

在这种情况下,用表格排版的话会简单一些,而且需要的代码量也少一些(td, tr总比div短吧),而且对需要限制每行显示元素的个数有规定的情况下非常好用。这就是表格的优点之一了。

当然我们要紧记的是,一开始我们就要求那些图片是能自由“浮动”的,也就是说,每一行能同时显示尽量多的图片,无论窗口的大小。而这个是表格无法做到但是飘浮属性可以做到的事情。所以我们还是物尽其用吧:)

创建目录模式视图

既然我们已经知道如何创建浮动的图片表格了,那么现在就让我们来考虑一些别的技巧。现在我们希望做出一个竖行排列的图片清单,在没,在每张图片的旁边附有标题,编号,售价等信息。因此我们需要把原来的样式表的一大半都抛弃掉-,- 然后重新开始。我们只让body和脚注的样式保留下来,如列表2.4所示。基本上我们会回到工程刚开始的时候那样(见图2.1)

列表2.4 重新开始

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

重新飘浮

我们把标题等信息都放到图片的右边而不是下边,这样就不至于使整个页面显得太长。这一次我们只需要设置包含图片的链接的飘浮属性即可,而不需要整个div都飘浮起来,这样的话文字就可以落在右边了。

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

div.pic a.tn {float: left;}

</style>

因为整个链接飘浮了,所以链接的图片也随之飘浮起来,正如一个飘浮div之内的文字也会跟随一样。另外我们还会给div添加一点临时效果,一点小的边缘和边框让我们看看整个样式的内部结构。结果如图2.11所示。

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

div.pic {margin: 10px; padding: 0; border: 1px dotted gray;}

div.pic a.tn {float: left;}

图2.11 飘浮其实是蛮危险的……如果你粗心大意的话

寒到死……如果我们真的需要这种效果的话倒是蛮好的;但这根本不是我们想要的呀。

到底发生了什么?当我们飘浮某个元素的时候,它就会从正常的文档顺序流中独立出来,也就是说它不会参与它上一级的标记占用高度的计算。在这个例子里,每个div的高度不由图片所决定的(因为它是飘浮的),而是由它的信息列表所决定的。

不仅如此,飘浮元素是从它在正常的顺序流中应该开始的地方开始,然后由飘浮的方向决定的。在这个例子中,我们是向左飘浮的,因此第二个图片本应该在它所在的div的最上面开始,然后向左飘浮。但是现在的问题是,在浮到左上角之前,它碰到了第一张飘浮的图片(刚好在左上角顶住了一点点),因此它只好紧贴在第一张图片的右边,所以就出现了这种奇怪的“对角线”的效果了。同样的问题也处在第三、第四……张图片上面。

当然,要修复这个问题有很多种方法。如果我们要让每个图片所在的div都能够根据div里面的内容决定高度的话,我们可以把div也飘浮起来。在目前的浏览器中(也包括CSS2.1),一个飘浮的元素会自动根据它的子元素来决定高宽度的。不过我们倒是不希望这样,因为现在还在的虚线边界只是出于检查的需要才加上去的,等会还要去掉的。

这又是怎么了?@.@

上面的解释可能有点混乱,如果看不明白的话就请多看几遍吧(译者注:看不懂中文那是我的问题;不过在翻译问题解决之前请看原文 ^^)如果你看明白了,那么试想想看如果没有那些文字的话会有什么结果。基本上还是会有相同的效果的,只不过文字的存在使得事情更加复杂了。

所以我们将会采用清除飘浮(clear)这个属性,因为飘浮都是在左边的,所以我们只需要清除左边飘浮就行了。我们还会给div设置一个宽度,后面将会用到这个属性。

div.pic {margin: 10px; padding: 0; border: 1px dotted gray;

clear: left; width: 350px;}

(注:这里的clear: left大概可以这么翻译:“make sure that the left side of div.pic is clear of floating images”,也就是“确保div.pic的左边是不会有飘浮元素阻挡的”)

这样的话,每个div都会往下移一点,使得上下两张图片不会出现刚才那种第二张图片被第一张“顶住”的问题,如图2.12所示。

图2.12 飘浮的问题解决了

排列与放置

看看图2.12,我们发现了一个问题需要解决:肖像图的排列有点混乱。在一个表格当中图片会把单元格“撑大”,我们也就只需要右对齐就可以了,但是现在我们就没那么轻松了。还好我们可以给飘浮的图片链接加一点左边缘,然后把整个图片链接的宽度显式设为和肖像图一样的宽度(96px)就行了。(注:这样的话,左边缘 + 图片宽度 = 风景图的图片宽度了)

div.pic a.tn {float: left;}

div.pt a.tn {width: 96px; margin-left: 32px;}

</style>

由于我们把肖像图的宽度显式声明了,我们还需要给风景图显式声明宽度。现在这个属性不会有什么作用,不过以后也许就不一定了。

div.pt a.tn {width: 96px; margin-left: 32px;}

div.ls a.tn {width: 128px;}

</style>

呃...下面把那些难看的蓝色图片边框去掉吧。

div.ls a.tn {width: 128px;}

a.tn img {border: 1px solid #333; border-width: 1px 2px 2px 1px;}

</style>

一个比较暗色调的右和下边框可以制造一种比较隐蔽的“掉落阴影”效果。如图2.13中某些图片所示。

图2.13 图片排列好了,阴影也加上去了…

如果仔细观察一下图2.13,你会发现两个问题:第一个是图片边框和文字之间有一点点重叠,这是因为加上了边框之后整个图片的宽度就比它所在的那个链接的宽度要大了,因此我们应该增大链接的宽度来解决这个问题。实际上,下面我们会把链接宽度加得比图片宽度还要大一些,以防万一。

div.pt a.tn {width: 100px; margin-left: 32px;}

div.ls a.tn {width: 132px;}

第二点是你会发现列表项前面的圆点是覆盖在图片之上的,当然这个问题并非所有的浏览器上都有。如果我们要保留这些圆点的话这个就是一个问题了,但是正如我们下面所做的那样,这些圆点还是要拿走的。

替换圆点的原因

这个圆点是根据列表项的左边缘来决定的,它永远会在左边缘的左边一小段距离外出现。因为我们现在的列表项左边缘是直接贴在飘浮图片的右边缘上的,所以圆点就会跑到图片之上了。

a.tn img {border: 1px solid #333; border-width: 1px 2px 2px 1px;}

div.pic li {list-style: none;}

</style>

这对于防止重叠来说是好消息,不过这样文字和图片始终太挤了,因此我们用边缘和补白属性,把文字右移一点。另外我们还会给文字加一个左边框,这样我们就能看清楚列表的左边缘的位置了。设置好之后的效果如图2.14所示。

a.tn img {border: 1px solid #333; border-width: 1px 2px 2px 1px;}

div.pic ul {margin: 0 0 0 140px; padding: 0 0 0 0.5em;

border-left: 1px solid;}

div.pic li {list-style: none;}

图2.14 有了边缘和补白,文字和图片就不会那么挤了

汗,为什么是140像素呢?实际上,这140个像素的边缘是暗藏在飘浮的链接之下的,从文字的左边缘一直延伸到div的左边缘。如果你看看图2.14中的第二个div的话,你会发现那个div是一直延伸到图片链接的右边的。实际上这对所有的div都是这样,只不过在肖像图的时候能看得更清楚而已。

改进列表样式

现在我们把注意力放在列表上面吧。第一件要做的事情是把列表的边框去掉,因为他们开始给我们制造麻烦了。因此现在的div.pic规则应该是这样的:

div.pic {margin: 10px; padding: 0;

clear: left; width: 350px;}

类似的,div.pic ul规则就应该是下面这样的:

div.pic ul {margin: 0 0 0 140px; padding: 0 0 0 0.5em;}

这也弄好了之后,我们就该弄标题了。给它们设定一个粗体,sans-serif的字体会比较好看,另外在它们下面加上一条边框。恩,另外还得往下移大概半个em的大小,否则和链接图片在一条直线上的话不太好看。

div.pic li {list-style: none;}

div.pic li.title {font: bold small Arial, Verdana, sans-serif;

padding-top: 0.5em; border-bottom: 1px solid;}

</style>

这里我们给字体大小设置为小,因为sans-serif字体一般在比正常偏小一点的情况下比较好看。为了保持一致性,我们给剩下的列表项也设置小字体。

div.pic li {list-style: none; font-size: small;}

现在到编号和价格了。他们相对标题来说没有那么重要,所以给它们一种相对不太明显的颜色,另外还会进行右对齐和斜体等操作,给它们一点点强调(见图2.15)。

div.pic li.title {font: bold small Arial, Verdana, sans-serif;

padding-top: 0.5em; border-bottom: 1px solid;}

div.pic li.catno {color: #776; text-align: right;}

div.pic li.price {color: #776; text-align: right;

font-style: italic;}

</style>

图2.15 文字现在看上去好看多了。

我们本可以结束了,不过现在就让我们继续吧。如果编号和价格能够在同一行分开显示的话是不是会更酷呢?恩,酷倒不一定,不过肯定是更美一些。我们就这么做吧,而且要不加飘浮……为此我们要把价格往上移一行。要做到这点的话,我们得显式设置每一行的高度,否则在不同的浏览器上就有可能出现不在同一条直线上的情况,那就毁掉了我们的样式了。另外,还要把列表项的补白和边缘统统去掉。

div.pic li {list-style: none; font-size: small;

line-height: 1.2em; margin: 0; padding: 0;}

现在要把编号往左移动了,给它一个4.5em的右边缘。

div.pic li.catno {color: #776; text-align: right;

margin-right: 4.5em;}

下面我们只需要让价格往上移了。还记得那个行高度么?我们只需要给价格所在的列表项加一个负值的边缘,那么文字就会自动往上移了,如图2.16所示。

div.pic li.price {color: #776; text-align: right;

font-style: italic; margin: -1.2em 0 0 0;}

图2.16 负值边缘的设置果然出现了魔法般的效果……

给信息加边框

下面我们再进一步,在编号左边、编号与价格之间加一个垂直的边框,然后给整个信息加一个盒子式的边框。

对IE的观察

下面的部分对IE5.x基本上不适用,因为它不能分辨自动边缘,不过前面一些设定在IE6里面效果还是不错的,只要你还是在标准模式下(?)。

为了正确呈现我们所需要的边框,我们要给编号和价格设置非常相似的样式。基本的思想是,给每一个列表项分别设定一个宽度,然后把文字推到宽度范围内的最右边。为此我们给左边缘设置为自动,余下的为零。这样做的话,边框就能正确地落在宽度内的最左边了。效果如图2.17所示。

div.pic li.price {color: #776; text-align: right;

font-style: italic; margin: -1.2em 0 0 auto;

width: 4em; border-left: 1px solid;}

div.pic li.catno {color: #776; text-align: right;

margin: 0 4.5em 0 auto;

width: 4em; border-left: 1px solid;}

图2.17 更多的边缘魔法!

下面是给所有文字加上边框,这个问题就比较有技巧性了。如果我们只是给ul标记加一个边框和背景色的话,IE6会莫名其妙地让那些内容消失掉。因此,我们不要让IE6辨认出这个属性从而破坏在IE6下的布局。下面就是我们的做法了:

div.pic ul {margin: 0 0 0 140px; padding: 0 0 0 0.5em;}

html>body div.pic ul {background: #CCB; border: 3px double #552;}

div.pic li {list-style: none; font-size: small;

line-height: 1.2em; margin: 0; padding: 0;}

看到一开始那个html>body么?这是一个子选择器,在CSS2下面是完全合法的,但是IE就是死活认不出来,这样的话就可以避免这条规则对IE的影响了。

边框加好之后我们还需要把价格往左移一点点,这样它就不会贴着中间那个垂直边框了。对此只需要改动右边缘的大小:

div.pic li.price {color: #776; text-align: right;

font-style: italic; margin: -1.2em 3px 0 auto;

width: 4em; border-left: 1px solid;}

在最后,我们再在每张图片之间稍微分开一点。我们有两种办法:一种是给飘浮的图片链接加一个下边缘,或者给图片本身加一个下边缘。由于清除飘浮的原因,加上边缘是不会起作用的。为了避免一些IE上的bug,我们给图片本身加下边缘吧。

Clear的实现原理

清除飘浮(clear)的本质是提高被清除飘浮的元素的上边缘,使得它的边框的外沿刚好在上一个飘浮元素的下面。因此设置上边缘的话会被clear重载掉的。

a.tn img {border: 1px solid #333; border-width: 1px 2px 2px 1px;

margin: 0 0 1em;}

至此我们终于完成了目录模式视图的设计。最终效果如图2.18所示,样式表如列表2.5所示。

列表2.5 完整的目录视图样式表

body {background: #EED; margin: 1em;}

div#footer {clear: both; padding-top: 3em;

font: 85% Verdana, sans-serif;}

div.pic {margin: 10px; padding: 0;

clear: left; width: 350px;}

div.pic a.tn {float: left;}

div.pt a.tn {width: 100px; margin-left: 32px;}

div.ls a.tn {width: 132px;}

a.tn img {border: 1px solid #333; border-width: 1px 2px 2px 1px;

margin: 0 0 1em;}

div.pic ul {margin: 0 0 0 140px; padding: 0 0 0 0.5em;}

html>body div.pic ul {background: #CCB; border: 3px double #552;}

div.pic li {list-style: none; font-size: small;

line-height: 1.2em; margin: 0; padding: 0;}

div.pic li.title {font: bold small Arial, Verdana, sans-serif;

padding-top: 0.5em; border-bottom: 1px solid;}

div.pic li.catno {color: #776; text-align: right;

margin: 0 4.5em 0 auto;

width: 4em; border-left: 1px solid;}

div.pic li.price {color: #776; text-align: right;

font-style: italic; margin: -1.2em 3px 0 auto;

width: 4em; border-left: 1px solid;}

图2.18 目录样式的最终效果

扩展练习

尝试再现以下这些效果。

在联系表格视图中,尝试把标题放置在图片的下方,效果看上去像是把标题写在幻灯片的下边框上面那样。你也许会需要把图片的下边缘去掉,不过不要毁掉整个设计效果哦。不过要记住,由于CSS还不能做到文字的旋转显示(例如左转90度等),因此就不需要对肖像图进行改动了。另外就是长标题的问题,这个时候像overflow这样的属性也许就会有用了。

在画廊模式下,把编号和价格加回去,并且把他们设定在同一行内,而不是像传统列表那样分开两行。这能进一步改进画廊模式下的视图,而不需要大量改动整个设计。当然还要记得多加一点高度。

在目录模式下,尝试把图片放到右边而文字在左边。这样就意味着要对飘浮的方向进行改动了,另外对列表项的样式也要进行改动。



-