题外话:不好意思在第一篇的三周之后才交作业。本想继续写 Google 的搜索结果页的,看到豆瓣上有朋友留言说想学习豆瓣首页的写法,我看了一下,有写头。起初以为比较简单的,最后花了不少时间。但还是有疏漏或者不合理的地方,请直接指出,谢谢。
前言
- 下文中的例子以豆瓣用户登录后的页面为基础,各人显示的内容可能有所差别;
- 这次并不强求像素级的一致,特别是行距、间距部分可能有细微出入;
- 理解本文需要你对 HTML 和 CSS 有所了解,最好能够手写 HTML 和 CSS 代码;
- 详细阅读本文可能会花上你 15 分钟以上时间;
- 本文遵循 Code for the best, fix for the rest 原则。
一、分析结构
布局难点
豆瓣的首页是典型的三行两栏的布局,不过有特殊之处。除去头尾,中间的 两栏,左栏是自适应,右栏是固定宽度(350px)。这样的布局,如果不考虑先加载哪部分内容(及语义),有相当简便的写法。另外如果两栏都是百分比宽 度,那么也好处理。不过事实是右栏的宽度是固定的(并且我计划让左栏先加载)。固定宽度(或高度)是一件很危险的事,除非你也固定了文字大小,不然当文字 被放大显示后,很容易出错(不过用表格的话就不用考虑这么多)。
其他难点
- 左栏的新评论列表
- 我觉得那是一个有序列表(Ordered List),所以在代码中用
<ol>
标签;也可以用<dl>
或者直接写<div>
- 列表左侧的图片,是用户的头像而不是书的封面。所以我把
<img>
和用户名那一行写在一起。
- 我觉得那是一个有序列表(Ordered List),所以在代码中用
- 右栏的豆瓣推荐和友邻的样式
- 我们常见的是固定高度的块依次浮动排列,但是这里书名的长度不一、图片大小不一且底部对齐,浮动块的高度未知,我没办法,只能暂时限定高度。谁有办法请不吝告知。
在分析结构的时候,我们一定要知道,我们需要先写什么,然后再写什么。这直接影响到后面样式表的写法。并且我的建议是,当结构确定下来之后,不要轻易改动。
二、基本布局代码
参照 Yahoo! UI Lib Grids,我把上中下三行分别命名为 #hd
、#bd
、#ft
,是 #header
、#body
和 #footer
的缩写。关于 id
和 class
的命名,各自有各自的习惯。在 CSS 里面,一般习惯用中划线法(如 comment-list
)、下划线法(如 comment_list
)、骆驼命名法(如 commentList
)和帕斯卡命名法(如 CommentList
),我个人比较倾向于使用下划线法。
中间的两栏我命名为 #main
和 #sidebar
。哪部分先显示呢?我想左侧的新评论先显示可能更好一些,毕竟在大部分情况下它的宽度都大于右侧。于是在 HTML 里面 #main
要写在 #sidebar
前面,如下:
- <div id="hd"></div>
- <div id="bd">
- <div id="main"></div>
- <div id="sidebar"></div>
- </div>
- <div id="ft"></div>
样式表怎么写呢?#hd
、#ft
可以先不管,#bd
因为其内部有浮动,不能自适应高度,所以需要清除浮动,方法有很多。如果不清除浮动,那么 #ft
的内容就会“见缝插针”的显示在你不想见到它的地方。本文的例子,可以给 #ft
设定 clear: both;
,或者为 #bd
进行 easy clearing(参考 P.I.E. 上的文章)。
因为 #main
的宽度是自适应的,#sidebar
的宽度又固定为 350px
,在 HTML 里面又是 #main
在前,所以不能用简单的浮动(浮动的元素必须设定宽度,否则会根据内容取宽度),也不能用绝对定位,因为你不知道两者的高度。根据屏幕宽度不同,有时候是 #sidebar
比较高,有时候是 #main
比较高,使用绝对定位的话,下面的 #ft
显示就会有问题。所以我用了一种不常用的办法(我不太喜欢这种负值 margin 的写法),如下:
- #bd{
- padding-right: 410px; /* 因为有 padding 所以 clear float 不能简单地将 #bd 设置为浮动 */
- }
- #main{
- width: 100%;
- float: left;
- }
- #sidebar{
- width: 350px;
- float: left; /* 如果float right,在 IE 下有问题,这里 fix 一下 */
- margin-left: 60px; /* 栏间距,即 gutter */
- margin-right: -410px; /* 这一句很重要 */
- }
如果我们在 HTML 里面先写固定宽度的 #sidebar
,那么 CSS 相当简单了,只需将 #sidebar
浮动到右边,然后 #main
再 margin-right: 410px;
就可以了,很 solid。这样 #main
的宽度也自适应了。CSS 如下(实际项目中我会采用这种写法,本例不是):
- #sidebar{
- float: right; /* 注意在 HTML 里面 #sidebar 写在 #main 前面 */
- width: 350px;
- }
- #main{
- margin-right: 410px;
- }
三、左栏新评论列表
刚才说了,这里可以用 <dl>
、<ul>
、<ol>
或者 <div>
,用什么是个人习惯或者根据需要。我在这里用 <ol>
,其他的写法都可以由此扩展。HTML 结构代码如下:
- <ol>
- <li>
- <h3>这里是评论的标题</h3> <!-- Logo 和各部分的大标题已经使用了 h1 和 h2 -->
- <p>评论的作者头像<img>和其他信息</p>
- <p>评论的摘要</p>
- </li>
- ...
- </ol>
这里的图片是用户的头像,所以我觉得应该和用户名放在一起。那么这种写法,用绝对定位简便一些。再提一下,如果使用浮动,必须给浮动的对象设置宽度,不然其宽度就会根据内容计算,这里的 <h3>
就不大方便用反向浮动的方法,因为它需要自适应宽度(如果用反向浮动的方法,可以参考上面布局的 CSS 写法)。
好了,基本问题解释清楚,我们开始写这里的样式(注意要清除 <ol>
的 margin
):
- .comment{
- list-style: none;
- position: relative; /* 给头像的绝对定位一个参照 */
- width: 100%; /* 如果不设置宽度,在 IE 下有定位问题;参考 On Having Layout 一文 */
- }
- .comment h3{
- background: #EFE;
- margin-left: 75px;
- }
- .comment p{
- margin-left: 75px;
- }
- .comment .avatar{ /* 头像 <img> 的 class */
- position: absolute;
- top: 0;
- left: 0;
- }
如果我们把头像 <img>
单独提出来,不和用户名写在一起,那么可以不用绝对定位。不过在自适应的布局里,使用 float
来定位也是相当麻烦的一件事情。
四、右栏豆瓣推荐
最大的难点。因为书名长短不一致,导致浮动的块高度并不能够统一(如果不设置的话),这样对于第二排的浮动就会有影响。我没想出有什么好的办法可以解决这个问题,所以只能给一个不完美的写法(但这很常用):
- <ul>
- <li>
- <div><img src="..." alt="..." /></div>
- <p>书或其他 item 的名字</p>
- </li>
- ...
- </ul>
在图片周围增加一个 <div>
方便控制(看下面的 CSS)。豆瓣上的图片是大小不一的(真是灾难),本例简化为图片大小相同,这样不会耽误太多时间。
我把图片周围的 <div>
高度和 <p>
的高度分开,这样在放大文字的时候,可以保持相对良好的可读性(但还是有不足的地方)。样式表如下:
- .itemlst{
- width: 350px;
- margin: 0;
- padding: 0;
- }
- .itemlst li{
- width: 100px;
- padding: 0 8px; /* 使用 margin 在 IE 下会有 double margin 的 Bug */
- float: left;
- text-align: center;
- list-style: none;
- }
- .itemlst li img{
- padding: 10px;
- }
- .itemlst li div{
- width: 100%;
- height: 120px; /* 这样把图像所处的块高度统一在 120px */
- }
- .itemlst li p{
- float: left;
- height: 6em; /* 最多显示四行文字,再放大就不行了 */
- line-height: 1.5em;
- }
五、其他
- 因为 FF 和 IE 对于
border: 1px dotted #DDD
显示的效果不一致。所以一般我会用背景代替(本例没有这么做)。 - 文字大小的控制,在
body
中设置基准值small
,然后使用百分比控制其他所有的文字大小。具体可以参考Bulletproof Web Design,中文版图书也已经上市。另,这只是习惯而已,在国内制作网页请根据实际情况量力而为。 - 关于第四部分的写法,在另外的文章内有说明。
- 在 CSS 的一开始,设定
*{margin: 0;padding: 0}
,统一各个浏览器的细微的差别。 - 最后设置各部分的字体和元素间的间距,完成整个页面的制作。
查看最终效果(通过 Strict 验证,不过没什么意思 -_-)
IE 下会有些局部的差异,大家有兴趣的话,可以研究一下,这里仅为 Firefox 服务。
六、我们学到了什么
- 利用
float
进行布局,特别是第二部分里面的第二种写法很常用; - 利用
position: absolute;
和position: relative;
进行局部定位; - 列表项(
<li>
)的浮动块状显示; - 在制作符合标准的页面时,需要考虑 resizing window 和 change font size 的问题。