标准化设计解决方案 - 标记语言和样式手册
Web Standards Solutions The Markup and Style Handbook
Part 1: Get Down With Markup 从标记语法谈起
Chapter 1 清单
在网络上几乎每个页面都能找到清单. 超链接清单;购物车物品清单;你中意的电影清单...甚至是整个网站的导航清单.可能在某些人看来,清单的建立是随心所欲的,但是我们要去探索发现的正是如何建立清单以及集中几种常用方法的优缺点.稍后,我们会列出几个如何美化普通清单一集他们的优缺点的示例来.
咱们去购物吧
最初,我打算用一个细目清单(洗衣清单)来作为本章的示例,但是很快的,我就意识到,我根本不知道这种清单中应该包括那些细目,所以...看在示例的份上,就用食物来举例吧!
让我们设想,你需要把一个食品清单放到你自己的网站上去,你可能会为为什么要把食物清单放到网站上去而感到不解,厄,这个可能就离题了,我们只是需要一个可以开始为清单思考的理由罢了...
在页面上,假设我们想让清单看起来像......好吧,看起来就像一个清单 — 也就是一长串垂直的列表,里面的每项内容独占一行:
Apples
Spaghetti
Green Beans
Milk
看起来非常简单,不是吗?和页面设计开发的许多方面类似,我们能够通过很多不同的方法达成相同(或者类似)的效果.与这本书后面所有的示例相同的,我将以eXtensilble HyperText Markup Language(XHTML)的观点来展现所有示例 — 并且确认选用的方法都使用正确的标记语法,遵照World Wild Web Consortium (W3C)所制定的各种标准.
我们可以轻松的在每个项目后面加上个<br />标签就搞定了,或者也能使用各种清单项目标签来完成这个工作,现在我们就来看3种完全不同的方法,以及每种方法的特点.
#p#
提问时间
下面哪种方法最适合建立食品清单?
方法 A: 用 <br /> 换行
Apples<br />
Spaghetti<br />
Green Beans<br />
Milk<br />
方法A的确是一种被广为传用的方法,可能有数百万个页面使用过,事实上,我相信我们中的每个人都会偶尔因为使用了这种方法而感到内疚,对吧?我们希望在清单中的每一项都独占一行,而加入了换行标签(在这里使用的是符合xhtml标准的自关闭标签<br />)就会在每个项目后面生成断行,这就是他所有的效果了,看起来,挺管用的.
但是,如果我们想要给这个食品清单加上与其他页面元素不同的样式的时候该怎么办呢?比方说:如果想让清单的所有链接的颜色变成红色而不同于默认的蓝色,或者想要改变字体的大小时该怎么办呢?真的我们什么都做不了,我们被为整份html文档设定的字体风格(如果有设定的话)限制住了.同时,如果在清单外面没有任何标签围绕,我们就没办法为清单制定一个独特的css规则.
折行
如果我们在清单中加入一个类似"Five Foot Loaf of Anthonys Italian Bread".根据这个清单在页面里摆放的位置,在水平空间不足或者浏览者的浏览器视窗比较窄的情况下,过长的项目就会冒着折到下一行的风险.
同时我们也要考虑到视力不佳的用户可能会把预设的字体大小改大以便增加可读性,我们认为能够像 图1 - 1 一样把项目轻松的布置在窄栏里,但是很有可能会像 图 1 - 2 这样在意料之外的地方发生断行,读者调大字体时,设计的样式就完全变样了.
图 1 - 1 预设文字大小的范围
图 1 - 2 调大文字大小后的相同内容
唔......现在,我想我应该要买面包是没错,但是在 图 1 - 2 里,面包上面的两行字实在感到疑惑.
在使用小屏幕装置像是移动电话或者PDA阅读长行时,类似的换行问题就会展露它丑恶的嘴脸,骨灰级的科技爱好者可能会随手带着记录购物清单的Palm Pilot(而不是传统意义上的纸和笔)当他在超级市场里面闲逛的时候,最后却在货架中寻找一种叫"Anthonys Italian"的东西.
在这里我要在本质上阐明一个观点 - 使用方法A ,并没有把阅读网页时的这些设计师们所无法控制的变数考虑在内.
#p#
方法 B: 会咬人的小圆点
<li>Apples<br />
<li>Spaghetti<br />
<li>Green Beans<br />
<li>Milk<br />
大多数成熟的浏览器在解析<li>标签时都会在清单项目的左侧加上圆点符号,你能通过方法B来达到这个效果,在需要圆点符号时加入<li>标签.但是如果<li>标签没有被包含在适当的父标签中时,那有些浏览器不会显示出圆点符号,适当的父标签包括强大的<ul>以及<li>的另一个父标签<ol>(有序清单),这个会在稍后有更多的讨论.
圆点符号的出现在某种程度上的确能够帮助解决换行问题,每个食品项目在左边会有小圆点符号,如果某个项目过长折行的话,旁边没有小圆点符号应该就可以很明显的看出这并不是全新的项目,但是方法B仍然有显示结果意外的问题:它并不符合标准.
麻烦检查一下
根据W3C的XHTML 1.0规范,所有的标签最后都必须要闭合起来 — 如果我们还是继续使用上面示例中的写法,让所有的<li>保持开放状态的话,那就太丢脸了!
在行末使用<br />标签来模拟正确的无序清单自动换行的显示效果,但其实我们有更好的方法.
一向以来,养成编写正确的标签语法的习惯非常重要,正确的编写标签语法,我们可以不必在未来担心由于没有闭合标签或者不正确的嵌套元素所带来的问题.如果有人阅读这些源代码的话,也可以使他们更加深入的理解源代码想要达成的效果.
记得善用W3C的在线检测工具(http://validator.w3.org/)来检查你提交的URI或者上传的文档,最终你会觉得这样做非常值得.
#p#
方法 C: 接近了
<li>Apples</li>
<li>Spaghetti</li>
<li>Green Beans</li>
<li>Milk</li>
方法C更加的接近完美的解决方案了,但是还是悲惨的失败了,原因还是非常明显:这仍然不符合标准的标记语法.
我们已经把<li>标签关闭了,因为<li>是块级元素(block-level),因此在使用上可以去掉<br />标签,这样每个项目都独占一行,但是,我们却漏了它的外层结构,缺少了一个表示"这群项目是一个清单!"的元素.
从语义化的角度看这个问题也非常重要 — 清单是一组项目归属在一起,因此我们应该为它们加上这样的标签,此外,使用正确的清单标签能清楚告诉浏览器,软件或者显示设备"这组项目是个清单!",语义化标签的意义就在于将内容根据他们所属的类别进行结构性的搭建.
块级(block-level)与行内(inline): HTML元素可以分为块级与行内两大类型,块级元素会从新行开始,最后接着一个断行,而行内元素则会与其他的行内元素显示在同一行内,块级元素可以包括其他块级元素和行内元素,而行内元素里面不能包含块级元素.
块级元素包括:<div>,<h1>-<h6>,<form>等等,行内元素包括:<span>,<h3>,<em>,<q>等等.
如果以纯XML的角度来看我们的食品清单,或许我们会使用这样的方式进行标注:
<grocerylist>
<item>Apples</item>
<item>Spaghetti</item>
<item>Green Beans</item>
<item>Milk</item>
</grocerylist>
整个清单有一个容器元素<grocerylist>,所有的食品项目都包含在里面,以这种方式归类项目,可以基于XML的应用轻松的从清单里面抽取出所有的项目.
举例来说,一个开发者需要编写一份XSLT样式表,将这个清单转成xhtml,纯文字,甚至是pdf文件,因为列表项目的结构表现的非常清晰,所以程序可以轻松的获取信息并作出一些有用的处理.
虽然在这本书里我并不直接处理XML,但是这些原则也适用于XHTML世界,如果文档使用非常语义化的标签结构,将可以提升文档今后的灵活度,不管是为结构清晰的文档加上css样式表还是修改容易理解的文档 — 只要提供正确的结构,就能节省许多今后在维护时可能浪费掉的时间.
接着,我们仔细的看看方法D,看看这些怎么样结合在一起 — 一个能被大多数浏览器和屏幕阅读器识别并显示的文档,同时又允许我们使用各种不同的方法为文档加上样式.
#p#
方法 D: 愉快的包装者
<ul>
<li>Apples</li>
<li>Spaghetti</li>
<li>Green Beans</li>
<li>Milk</li>
</ul>
是什么让方法D变得如此特别?首先,它的语法完全正确,正确的无序清单具备了<ul>容器元素,同时每个项目都已<li>元素闭合起来.到这里你会想问,我们花费了那么多力气只来示范为了正确而正确?我们来看看这样做能带来的好处:
由于我们正确的标记了我们的食品清单,每个项目都会独占一行(因为块级元素<li>的关系),而且大多数浏览器会给每个项目的左边增加一个小圆点符号,并且进行正确的行内缩进换行.(见图 1 - 3)
图1 - 3
PDA,移动电话,或者其他的小屏幕设备的用户也可以看到清楚的,关系明确的组织方式,由于我们告诉了这些设备这些资料的类型(在这个示例里是清单),因此这些设备能够根据自己的能力决定怎样显示才能达到最好的效果.
如果因为放大字号或者缩小浏览器视窗宽度等原因造成换行,那么被换行的文字会行内缩进到与第一行文字对齐的位置,所以不管浏览器环境如何,都可以轻松的识别每个清单项目.
#p#
概要
我们已经针对每种可能的方法进行讨论了,现在让我们快速的回顾一下刚才讨论过的东西:
方法A:
无法为清单加上独特的样式 在狭窄的列里或者小屏幕设备上,较长的内容可能会因为换行而造成误解
缺乏语义性
方法B:
增加小圆点符号来帮助识别每个项目,但是一些浏览器会在缺失父级标签<ul>时可能不显示小圆点符号
没有放在<ul>中,缺少闭合标签</li>意味着难于加上样式
不标准
方法C:
加上了闭合标签</li>后就不需要<br />标签了 省略了<ul>元素使得我们难于为这个清单添加特定的样式
不标准
方法D:
符合标准!
使文档语义化,结构性
大多数浏览器都会在每个项目左边显示小圆点符号
在大多数浏览器上都会在换行后行内缩进
很容易就可以定义特定的css样式
正如你所见,你可以从一个看起来很简单的问题上获得不少知识.就算是你已经在你所有的页面上都是用了方法D,还是可以你为什么这样做比较好,我们会在这本书里一直探索"为什么"的问题,让你在各种情况下选用最恰当的方法.
#p#
技巧延伸
让我们利用我们构造出来的食品清单来试看看几种用定义css样式的方法,我们将抛开预设样式,加入自定义的圆点符号,接着把它转成横向,把它变作一个导航条.
扔掉圆点
"我真的不喜欢食品清单里的那些个小圆点,我想我还是用回<br />吧."
不需要回到老习惯 — 我们仍然可以使用我们结构化的无序清单,然后使用css关闭掉小圆点符号和行内缩进,关键在于我们保留了清单的结构,然后以css具体的呈现出来.
首先,加上一段去掉圆点符号的css规则:
ul{
list-style:none;
}
显示的结果见图1 - 4
图 1 - 4 去掉小圆点符号
接着我们来去掉行内缩进,根据预设值,所有无序清单左边都会留有一些内补丁(padding),但是不用担心,我们可以随心所欲的裁掉:
ul{
list-style:none;
padding-left:0;
}
显示结果可见图1 - 5
图 1 - 5
虽然图 1 - 5 看起来和使用了几个<br />标签的效果几乎一样,但是它还是符合标准的,结构化的无序列表 — 不管什么浏览器,设备都能正常显示,如果必要的话只需要更新几条css规则就能换上不同的样式了.
#p#
使用自定义圆点符号来完成自己的想象
或许你想要在清单里保留小圆点符号,但是不想用浏览器无趣的默认设置,更像用自己的小圆点图案.有两种方法可以达成你想要的 — 而我更推崇第二种方法,因为它可以在各种浏览器之间更好的兼容.
第一种方法是用 list-style-image 属性来指定用来替代默认小圆点的图片名称.
ul{
list-style-image:url(i_hot.gif)
}
这是最简单的方法,但是它会在不同浏览器之间的图片垂直对齐位置上有所不同,有些浏览器会把图片和项目文字中线对齐,也有的会把图片放得稍微高一点,它们之间有一点不一致.
为了避免 list-style-image 造成的几个流行浏览器之间的对齐问题,我比较喜欢用一种替代方法:把图片作为每个<li>元素的背景.
首先,我们要去掉默认的圆点,然后再加上我们自己的背景图片:
ul{
list-style:none;
}
li{
background-image:url(i_hot.gif) no-repeat 0 50%;
padding-left:25px;
}
no-repeat 会告诉浏览器不把背景图片进行平铺操作(默认会平铺),而0 50%会告诉浏览器把背景图片放置在距离左边 0 像素,距离上面 50% 的地方,让背景图片 i_hot.gif 根据中线对齐.我们也可以用精确的像素来指定位置,比如说 0 6px 会让图片放置在距离左边0像素,距离上面 6 像素的位置上.
我们还要在清单项目的左边加上17像素的内补丁(padding),以便我们把宽20像素高11像素的图片能够完整显示出来,同时又留有一点空白,而不会和文字有重叠.这些数据应该根据你所使用的图片尺寸进行调整( 图 1 - 6 )
图 1 - 6 自定义圆点图片的清单
#p#
导航清单
在我的个人网站(www.simplebits.com)里我分享了几种将无序清单转化为水平导航条的方法,用普通的,结构化的XHTML就像我们的食品清单示例那样创造一个类似分页标签(Tab)的效果.
我们把那个食品清单转换成一个网上超市的导航条(这个超市只卖几种东西就是了...).
我们想要这个导航条以水平的方式呈现,并且能够在鼠标划过,选中时有某种强调显示,以便我们模拟分页标签的效果.
首先,我们为清单加上一个id,这样我们就可以为它单独定义css样式了,同时我们也将把每个食品项目转成链接.
<ul id="minitabs">
<li><a href="/apples/">Apples</a></li>
<li><a href="/spaghetti/">Spaghetti</a></li>
<li><a href="/greenbeans/">Green Beans</a></li>
<li><a href="/milk/">Milk</a></li>
</ul>
现在,开始加上一些辅助的css:
#minitabs{
margin:0;
padding:0 0 20px 10px;
border-bottom:1px solid #696;
}
#minitabs li{
margin:0;
padding:0;
display:inline;
list-style:none;
}
在这里我们已经完成了去掉默认圆点符号和行内缩进的工作,我们也把 display设置成inline,往垂直清单转化成水平清单迈出了第一步,同时我们也加上了底部边框以便区分出整个链接组.
把清单转化成水平导航条的第二步,是将我们的链接全部浮动到左边显示,我们同样为所有的超链接加上简单的样式:定义外边距和内补丁的大小:
#minitabs {
margin: 0;
padding: 0 0 20px 10px;
border-bottom: 1px solid #696;
}
#minitabs li {
margin: 0;
padding: 0;
display: inline;
list-style-type: none;
}
#minitabs a {
float: left;
line-height: 14px;
font-weight: bold;
margin: 0 10px 4px 10px;
text-decoration: none;
color: #9c9;
}
在这里我们将清单中所有的元素都定义float:left,是为了让他们能水平显示排列于一行之内,同时我们也加上了了一些色彩,把链接改成粗体,拿掉了链接底部的下划线.
然后,为鼠标滑过或选中的链接创建一个模拟分页标签的边线:
#minitabs {
margin: 0;
padding: 0 0 20px 10px;
border-bottom: 1px solid #696;
}
#minitabs li {
margin: 0;
padding: 0;
display: inline;
list-style-type: none;
}
#minitabs a {
float: left;
line-height: 14px;
font-weight: bold;
margin: 0 10px 4px 10px;
text-decoration: none;
color: #9c9;
}
#minitabs a.active, #minitabs a:hover {
border-bottom: 4px solid #696;
padding-bottom: 2px;
color: #363;
}
#minitabs a:hover {
color: #696;
}
为了强调链接,我们在鼠标划过或选中时增加一个4像素高的底边,我们也可以使选中的<a>标签保持强调效果,只要加上class="active":
<li><a href="/spaghetti/" class="active">spaghetti</a></li>
这个 active类别与 a:hover的共用相同的css样式.(图 1 - 7)
图1 - 7
我在自己的网站(www.simlpebits.com)以及2003年7月重构Inc.com(www.inc.com)里面都用到了这个技巧.如果你需要更多的示例代码,可以自由访问这两个网站并查看他们的源代码.
只需要加上一些内补丁和边框,就可以达到各种类似分页标签的效果了,到目前为止,我们甚至连一张图,一句javascript都没有使用,而仅仅只用到了基本的xhtml结构就构成了我们的食品清单,这实在是太棒了!
迷你分页标签的外观
如果你想要和平常的,方方正正的css边框不太一样的效果的话,只需要作出一点点小修改,我们就可以使用图片来创建有趣的导航条了.
我们使用和之前完全一样的无序清单,以及十分类似的css:
#minitabs {
margin: 0;
padding: 0 0 20px 10px;
border-bottom: 1px solid #9FB1BC;
}
#minitabs li {
margin: 0;
padding: 0;
display: inline;
list-style-type: none;
}
#minitabs a {
float: left;
line-height: 14px;
font-weight: bold;
padding: 0 12px 6px 12px;
text-decoration: none;
color: #708491;
}
#minitabs a.active, #minitabs a:hover {
color: #000;
background: url(tab_pyra.gif) no-repeat bottom center;
}
这段css大概看起来和上一个示例中的几乎一样,最主要的区别在我们用 background-image 定义了在鼠标划过或选中的时候显示在链接底部中间的图片来代替了原本的4个像素高的底部边框.(图 1 - 8)
图 1 - 8: 使用背景图的迷你分页标签导航
这里的技巧在于选择一个足够窄的图片,必须能够塞进最短的导航条项目下,这样一来我们只需要一张图片来强调导航链接而不必为各种不同宽度准备不同的图片,当然,在你自己的项目中,你可以选择各种图片使用(图 1 - 9):
图 1 - 9: 使用其他图片的例子
这些迷你分页标签的源码和示例都可以在www.simplebits.com/tips/ 找到,更多的为清单添加样式的方法可以参考 Mark Newhouse在A List Apart杂志上发表的"Taming Lists"的文章(www.alistpart.com/stories/taminglists/)