HTML标记语言——表格标记

点击这里返回脚本之家 HTML教程 栏目.
上文:

标记语言——标题


原文出处

标准化设计解决方案 - 标记语言和样式手册
Web Standards Solutions The Markup and Style Handbook


Part 1: Get Down With Markup 从标记语法谈起


Chapter2 邪恶的表格?


你知道吗?不知何时开始,使用表格居然变成充满罪恶的举动了?的确,以web标准编写网页的最大迷思就是"不要再使用表格了,永远不要!" 听起来表格就和瘟疫一样必须躲开,必须密封起来丢进满是灰尘的柜子里,当成是网络发展时代早期流传下来的古董保存起来.
如此的厌恶从何而来呢? 或许一开始十分单纯,至少拥有一个好的理由.很多人会理直气壮的宣扬抛弃传统的表格嵌套与补空gif图片的布局方式,改用灵活的结构化的css布局方式的好处.我们可能就开始抽丝剥茧的去掉所有的表格,甚至开始顽固的坚持把所有的表格驱逐出去 — 根本不分场合.
书中稍后我们会看到css布局的方法和这样做带来的所有好处.但是现在我们还是先来看看如何在适当的场合—也就是标记数据列表的时候使用表格.我们会研究几个简单的方法是我们的数据列表变得更容易使用,更漂亮.

完全就是表格


在标记列表数据时,我们绝对没有理由不去用表格标签.但是等等,什么才是列表数据?这边有一些例子: 日历 电子数据表 图表 时间行程表
对这些例子以及许多其他情况来说,必须使用非常复杂严格的css特效才能让资料看起来像表格,或许你能想象,用巧妙的css浮动,定位所有项目之后得到的是不兼容的矛盾的结果,更别提拿掉css之后,准确读出每笔资料大概会成为不可能完成的任务.事实上,我们不必畏惧表格—我们应该用他们设计之初的目标来使用它们.

适合所有人的表格


表格找来谩骂的原因之一是如果没有小心使用的话会存在可用性缺陷.举例来说:屏幕阅读程序难以正确读出内容,而小屏幕设备经常被用来布局的表格扰乱,但是我们有一些简单的方法增加列表数据表格的可用性.同时建立灵活的结构,方便未来以css设定样式.
让我们看看 图3-1 中的简单示例,这是美国棒球联赛的联盟记录:

图 3-1:典型的资料表示例
也许对红袜队球迷来说这是非常郁闷的统计资料,不过图3-1的却是列表资料的完美示范.它有三个表头(year,opponent,season record(w-l)),跟着是四年份的资料.在表格上面的是表格标题,说明了表格的内容.
标记这个资料表格的方式十分直观,我们或许会以这样的代码完成这个工作:
<p align="center">Boston Red Sox World Series Championships</p>
<table>
<tr>
<td align="center"><b>Year</b></td>
<td align="center"><b>Opponent</b></td>
<td align="center"><b>Season Record (W-L)</b></td>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

这样显示的结果应该和图3-1十分相似,但是,我们可以在这个基础上加上一些改进.
首先,我们能用更加语义化的<caption>标签来存放"Boston Red Sox World Series Championships".<caption>标签需要紧跟在<table>起始标签后面,通常用来存放表格的标题或者表格资料的说明.
看上去,它更容易让使用者看出表格的主题,同时也能够帮助以其他方式得知网页内容的人.
让我们拿掉开头的那个段落,并加入正确的<caption>:
<table>
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<td align="center"><b>Year</b></td>
<td align="center"><b>Opponent</b></td>
<td align="center"><b>Season Record (W-L)</b></td>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

重要的是,标题必须快速传达后面资料的主题,根据默认设置,大多数可视化浏览器将<caption>标签内的文字居中显示在表格的最上面,当然,我们稍后可以使用css来改变默认设置的样式 — 本章的技巧延伸中会讨论这个问题.事实上,现在标题位于独特的标签内,正好让我们之后的修改工作变得轻松简单.
#p#

加上摘要


另外,我们也能为<table>标签加上summary属性,进一步解释这个表格的目的和内容,摘要属性对非可视化浏览器尤为重要,这能帮助它们解说表格的内容.
以下是为示例表格加上摘要属性的代码:
<table summary="This table is a chart of all Boston Red Sox World Series wins." >
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<td align="center"><b>Year</b></td>
<td align="center"><b>Opponent</b></td>
<td align="center"><b>Season Record (W-L)</b></td>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

表格的表头


在建立数据表格时,善用表头是件很重要的工作.在标记重要单元格时,我们可以发挥<th>标签的作用,而不是使用<b>之类在显示上暗示用户这个单元格是重要的的显示效果标签.就像我们在第二章中使用标题标签标记段落标题一样.
可视化浏览器或许会以粗体居中的效果显示<th>标签中的内容,但是我们依然可以用<th>标签的独特性,稍后再给这些重要的内容加上不同的样式,以便于存放在<td>内的一般资料及进行区别.
除显示效果的优势外,使用<th>标签也能帮助非可视化浏览器 — 这部分我们稍后进行深入讨论.
示例表格中的表头是最上面的那一行: Year,Opponent和Season Record(W-L).我们来把刚才的显示效果标签替换成正确的表头标签:
<table summary="This table is a chart of all Boston Red Sox World Series wins.">
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<th>Year</th>
<th>Opponent</th>
<th>Season Record (W-L)</th>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

使用<th>标签来标记表头单元格和图3-1中的效果是一样的,让我们来看看为什么这个方法比较好:
我们不必使用额外的显示效果标签让表头突出显示在资料内容之外.
根据默认设置,大部分可视化浏览器都会以粗体居中的效果展示<th>标签中的内容.让使用者轻易分辨出表头和表格内容的区别.
由于它和<td>标签是相对独立的,因此我们能为表头加上与资料内容不同的样式.
使用表头标签的其他好处我们在接下去的章节中继续讨论.
#p#

表头与数据的关系


我们可以利用headers属性把表头和对应的<td>中的数据关联起来,使屏幕阅读器能更容易为需要的人们组织表格内容.在使用了这个属性之后,屏幕阅读器将能更符合逻辑的读出表格内容,而不是像平常一样死板的从每列最左边读到最右边.
我们继续使用红袜队战绩表当作例子来示范使用方法.首先,我们需要为<表格中的每个<th>加上一个唯一的id,接着再为每个资料单元格加上headers属性,对应正确的表头.
为每个表头加上id很简单,就是这样:
<table summary="This table is a chart of all Boston Red Sox World Series wins.">
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<th id="year">Year</th>
<th id="opponent">Opponent</th>
<th id="record">Season Record (W-L)</th>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

我们为每个表头id选择简短的有描述意义的名称,接着我们再为每个资料单元格加上适当的headers属性,让内容匹配正确的表头id:
<table summary="This table is a chart of all Boston Red Sox World Series wins.">
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<th id="year">Year</th>
<th id="opponent">Opponent</th>
<th id="record">Season Record (W-L)</th>
</tr>
<tr>
<td headers="year">1918</td>
<td headers="opponent">Chicago Cubs</td>
<td headers="record">75-51</td>
</tr>
<tr>
<td headers="year">1916</td>
<td headers="opponent">Brooklyn Robins</td>
<td headers="record">91-63</td>
</tr>
<tr>
<td headers="year">1915</td>
<td headers="opponent">Philadelphia Phillies</td>
<td headers="record">101-50</td>
</tr>
<tr>
<td headers="year">1912</td>
<td headers="opponent">New York Giants</td>
<td headers="record">105-47</td>
</tr>
</table>

在为表头和内容之间建立对应关系后,屏幕阅读器可能会议这样的方式读出表格的每一行内容: "Year:1918,Opponent:Chicago Cubs,Season Record(W-L):75-51",比起从左到右读出每格内容的方法来说,这样就有意义多了.
让每个<th>具有唯一的id还有其他的好处,我们可以使用这个辨别依据,设定特殊的css规则,在本章最后的技巧延伸终究会讨论这个方法.
#p#

使用abbr属性


在之前的示例中,或许你会觉得表头中"Season Record (W-L)"用语音合成器来念实在太长了一些,此时,只要加上abbr属性,我们就能缩短发音时的内容,同时又为可视化浏览器保留了<th>单元格中的原始文字.
<table summary="This table is a chart of all Boston Red Sox World Series wins.">
<caption>Boston Red Sox World Series Championships</caption>
<tr>
<th id="year">Year</th>
<th id="opponent">Opponent</th>
<th id="record" abbr="Record">Season Record (W-L)</th>
</tr>
<tr>
<td>1918</td>
<td>Chicago Cubs</td>
<td>75-51</td>
</tr>
<tr>
<td>1916</td>
<td>Brooklyn Robins</td>
<td>91-63</td>
</tr>
<tr>
<td>1915</td>
<td>Philadelphia Phillies</td>
<td>101-50</td>
</tr>
<tr>
<td>1912</td>
<td>New York Giants</td>
<td>105-47</td>
</tr>
</table>

我们加上了 abbr="Record" 后,屏幕阅读器会读出表头使用简短的版本后的"Record".

<thead>,<tfoot>和<tbody>


在这里我还想提一下三个与表格相关的标签.它们不仅能为表格结构提供更精确的语义,同时也为css提供额外的标签,让你在设计表格行的样式时不用为<tr>标签设计那么多的class.
引用一段W3C在HTML4.01规格中对这些标签的说明(http://www.w3.org/TR/html4/struct/tables.html#h-11.2.3):

引用:

表格行能够以thead,tfoot和tbody标签分成表头,表尾以及数目不限的表格主体.这种分类法让浏览器支持独立卷动表格主体的功能.打印长表格时,表头和表尾也能在包含表格资料的每一页上重复出现.
因此,使用使用这种分类方式也能让支持独立表格主体的浏览器使用者更容易阅读表格内容,特别是长表格.
<thead>与<tfoot>必须出现在<tbody>之前,让浏览器与其他设备能够先载入这些内容,以这种表格行分类方式标记表格看起来是这样的:
<table>
<thead>
<tr>
...table header content...
</tr>
</thead>
<tfoot>
<tr>
...table footer content...
</tr>
</tfoot>
<tbody>
<tr>
...table data row...
</tr>
<tr>
...table data row...
</tr>
<tr>
...table data row...
</tr>
</tbody>
</table>

你会发现,表头和表尾资料以<thead>和<tfoot>标签包围,放在表格数据行之前.
就像我之前所说的那样,这些标签不仅能为表格提供更精确的语义,还能给css提供样式锚点让你为这些特定内容设置css规则,而不必为每个<tr>设计那么多的class.
举例来说,如果我们只想给数据区块(以<tbody>标记)设定与其他区块不同的背景色.那么我们只需要写这样一段css就能达到目的:
tbody {
background-color: gray;
}

如果没有tbody标签的话,我们需要为每个想要加上灰色背景的<tr>标签添加class属性.有意义的标记方式经常能使之后用css设定样式的工作变得十分轻松.这就是个好例子.
#p#

表格邪恶吗?


我想,如果我们根据表格标签设计之初的目的好好使用的话,那么答案就肯定是"不!".滥用表格创建复杂嵌套的布局的行为理所当然会遭到谴责,但是表格的确会给资料区块提供它需要的良好的结构.
我们不能在整本书里都叙述创建完美表格所需要的各种技巧,因此就此打住,希望你已经开始知道如何创建简单的又具有可用性的方便css修饰的简单表格.
谈到样式,让我们用几种不同的css技巧修饰一下之前的示例.

技巧延伸


与之前章节一样,我们用灵活的语义化的结构化的标记为基础,然后用css给他加上一些样式
首先,我们先来看看简单的边框技巧,在示例上创建单线边框,然后我们再为表格标题和表头加上独特的样式

建立边框


已经对border默认属性的3维效果感到厌倦了么?我也是.一般来说,为table标签加上border="1"就会与图3-1的效果类似,当然你也能换个方法,这边有一个用css做出漂亮整洁边框的诀窍.首先,我们给每个<th><td>单元格两侧(右侧和底部)加上一像素的边框:
th, td {
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}

只加上两侧边框,是建立各处边框等宽又同时让大部分流行的浏览器能够正确显示的关键所在.如果我在四周都加上边框,那么边框的顶部和左侧会在单元格排列时造成重叠,在稍后的示例中,我会给出一种只用一条border规则就达成小童效果的方法.
你会发现图3-2中的整个表格只缺少了最顶部和最左侧的边线,为了补齐边框,我们给<table>元素加上样式相同的border-top和border-left属性
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
}
th, td {
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}


图3-2:为th和td加上两侧边线的表格示例

图3-3 补齐边线后的表格示例
#p#

去掉间隙


现在我们已经有了个完整的表格了,但是边框之间的间隔是怎么回事?不幸的是,由于大多数浏览器会默认设置一点外补丁,因此就会露出这些令人讨厌的间隙了.
我们能做的是为表格元素加上border-collapse属性来去掉这些间隙,得到我们想要的样式.
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
border-collapse: collapse;
}
th, td {
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}

在为border-collapse加上collapse属性后,我们就能看到精确的单线边框样式了,如图3-4

图3-4:使用了border-collapse属性后的表格示例

不支持IE for Mac的版本


除了Internet Explorer for Mac之外,其他的浏览器都支持把css简写成这样:
table {
border-collapse: collapse;
}
th, td {
border: 1px solid #999;
}

要用哪一种方法,这当然由你来决定了,现在仍然有一些人再使用IE for Mac,而使用这个替代方法的话,会让他们看到一些边线的重复,如果你并不在意这件事情,那就使用简化的办法吧.严格来说,这只是个显示上的问题,表格功能丝毫不受影响.
由于我无法弃Mac狂热者于不顾(任何称职的网页设计师都应该这样),因此再往后的示例中,我还是会用IE for Mac也能正确显示的版本.

扩大空间


现在我们手上有了一个完美的表格,不过它看上去有点局促...让我们为手边的th,td规则加上一点内补丁,给它们呼吸的空间(图3-5)
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
border-collapse: collapse;
}
th, td {
padding: 10px;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}


图3-5:加上10像素内补丁的表格示例
你知道吗?如果用单一数值设定内补丁的话(比如之前的例子的10px),就需要给元素的四边都加上相同的设定值,你也可以按照顺时针顺序(上右下左)分别指定每一边的设定值.如果你把内部定设定为10px 5px 2px 10px的话,就会在顶部加上10px的内补丁,右侧加上5px的内补丁,底部加上2px的内补丁,左侧加上10px的内补丁.
另一条捷径:如果上下的设定值相同,左右的设定值也相同的话,你就只需要分别设定一次就可以了,如果设定了padding:10px 5px的话,就会在上下部加上10px的内补丁,在左右侧加上5px的内补丁.

图3-6:顺时针设定内补丁和外边界的顺序
#p#

调整表头的显示效果


我们可以轻松的给表头加上背景色,选用不同的字体,让表头更加的明显,由于我们是使用了<th>标签而不是直接在行内将内容设为粗体,因此我们不必加上任何其他的标签,就能直接为表头内容设定样式.
我们在标题下面也加上一点内补丁,同时还用不同的字体,颜色(当然是红色)以突出标题内容(图3-7)
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
}
caption {
font-family: Arial, sans-serif;
color: #993333;
padding-bottom: 6px;
}
th, td {
padding: 10px;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}
th {
font-family: Verdana, sans-serif;
background: #ccc;
}


图3-7:加上样式的标题和<th>

为表头加上背景图片


刚才我们为表格里的<th>元素加上了灰色背景,但是我们其实可以更进一步,用背景图平铺在格子里来作出漂亮的效果,举例来说,我们能用细致的灰色条纹模拟出许多Mac OS X中的窗口样式

小图片


首先我们用photoshop(或者其它你熟悉的绘图工具)建立一个小图片,在这个例子中,我们要制作一个2像素灰色和2像素白色交替出现的效果,因此图片只需要4像素高,宽度多款都无所谓,因为它会在<th>里平铺开来,做出我们想要的条纹效果.为了节省带宽,我们只做1像素宽(图3-8)

图3-8:1X4的像素条纹图片(放大后)

CSS


沿用刚才示例中的代码,我们需要修改的地方只有把背景颜色换成刚制作好的小图片路径,除非另外制定,否则根据默认设置,背景图会自动超每个方向平铺.
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
}
caption {
font-family: Arial, sans-serif;
color: #993333;
padding-bottom: 6px;
}
th, td {
padding: 10px;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}
th {
font-family: Verdana, sans-serif;
background: url(th_stripe.gif);
}

图3 -9是套用这个样式后的表格,表头部分分线了条纹背景,要实验其他的平铺背景图也很方便,你可以试试怎样才能为表头或资料做出最好看的效果,好好享受这个实验的过程吧.

图3-9:在表头使用平铺背景的示例
#p#

为ID指定图标


记得本章开始的时候我们为表格里的每一个<th>加上唯一的ID吗?那时我们把这些id与数据列表中的headers属性匹配起来,帮助非可视化浏览器的使用者了解表格的内容,现在我们能在另一个地方发挥这个id的功能了,那就是为每个<th>指定不同的图标.
图标路径会完全记录在css文件中,让你能够在网站重构,更新时轻易的替换,完全不必修改标签部分.

图标


我用photoshop做了三个独特的图标,分别用在示例中每个表头上:Year, Opponent与Season Record(W-L).图3-10就是这三个图标:

图3-10hotoshop制作的三个表头图标

CSS


加上css并不困难,因为我们为每个<th>都制定了独特的id,因此我们能直接用background属性来指定正确的图标.
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
}
caption {
font-family: Arial, sans-serif;
color: #993333;
padding-bottom: 6px;
}
th, td {
padding: 10px;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}
th {
font-family: Verdana, sans-serif;
}
#year {
padding-left: 26px;
background: #ccc url(icon_year.gif) no-repeat 10px 50%;
}
#opponent {
padding-left: 26px;
background: #ccc url(icon_opp.gif) no-repeat 10px 50%;
}
#record {
padding-left: 26px;
background: #ccc url(icon_rec.gif) no-repeat 10px 50%;
}

你应该注意到了,我们改用简写方式定义了背景样式,我们从th的定义中取出background:#ccc规则,并把它放到每个表头的图标名称旁边,这会使得我们的图标"坐"在我们指定的灰色背景上面,我们也在每个表头内容的左边留够图标的空间,不让文字覆盖上去,图3-11就是我们想要的效果:

图3-11:为每个<th>制定独特图标的效果
使用简写语法有明显的优点,然而,如果我们只以background属性定义图片,不定义背景色的话,就应该先取消掉先前在<th>中以background定义的背景色.

组合规则,简化内容


能够达到相同功能的另一种写法,是把每个表头里反复出现的规则(在这个例子中是背景图片,内补丁和位置)拿出来写在<th>定义一次就好了(因为它们的设定在每个<th>中的确都一样),然后只在#year,#opponent,#record定义内保留各自不同的设定值(也就是图片路径)
table {
border-top: 1px solid #999;
border-left: 1px solid #999;
}
caption {
font-family: Arial, sans-serif;
color: #993333;
padding-bottom: 6px;
}
th, td {
padding: 10px;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}
th {
font-family: Verdana, sans-serif;
padding-left: 26px;
background-color: #ccc;
background-repeat: no-repeat;
background-position: 10px 50%;
}
#year {
background-image: url(icon_year.gif);
}
#opponent {
background-image: url(icon_opp.gif);
}
#record {
background: url(icon_rec.gif);
}

这样稍微简洁一些了吧?借着整合相同规则,我们能够省下每次重复定义修改的时间和精力,以这个例子来说,看起来只差六个,半打而已,但是对大一些的样式表来说,节省的量就很可观了.

总结


在本章,我们不仅发现了表格并不邪恶,同时还深入了解表格之后,我们发现,他们很适合用来标记例表数据,而且仍然易于使用
我们更发现,只要加上一些样式,就能控制列表数据的显示方式,让他们变得十分具有吸引力,别再为使用表格而感到恐惧了.

HTML标记语言——表格标记