2.7. 表格

在文档排版过程中,我们经常接触表格,比如通讯录、比赛成绩、课程表等内容都是通过表格的形式呈现出来的。表格通常放在带有编号和标题的浮动区域内,以此区别于文章的正文部分,它是使用行和列来组织、整理、显示数据或信息的一种可视化方法。

通常,table)由指定数量的 row)和 column)构成; 有时被称为 记录record)或 向量vector), 有时也被称为 字段field)、参数parameter)或 属性attribute);行和列的交叉点被称为 单元格cell)。

![表的逻辑结构](../images/table_logical_structure.png)

表的逻辑结构

HTML 的设计者在描述 表格 时,绕开了 的概念,基于 HTML 元素的特点,使用“一个表格由一行或多行组成,每行由一个或多个单元格组成”这种更为简单的层次关系,如下图所示。

![HTML 如何描述表格](../images/table_html_structure.png)

HTML 如何描述表格

HTML 中,一个表格以 <table> 开始,以 </table> 结束,表格的每行table row)使用 tr 元素包含,行中用于包含 表格数据table data)的每个单元格以 td 元素表示。上面的表格的 HTML 代码就是:

<table>
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商1班</td>
        <td>张三</td>
        <td>85</td>
    </tr>
    <tr>
        <td>电商2班</td>
        <td>李四</td>
        <td>90</td>
    </tr>
    <tr>
        <td>电商3班</td>
        <td>王五</td>
        <td>80</td>
    </tr>
</table>

2.7.1. table

表格具有相对复杂的结构,table 元素是这个复杂结构的容器,所有其它表格相关的元素都应包含在 table 元素之内。

2.7.1.1. 宽度与对齐

可以使用 width 属性指定表格的 宽度,该属性的属性值是一个像素值或是一个百分比,后者的实际宽度以表格所在容器(如 body 元素所代表的整个浏览器窗口)的宽度为参照,如果容器宽度发生变化,表格的实际宽度也会随之动态调整变化。

当表格宽度小于其所在容器宽度时,可以使用 align 属性指定表格在水平方向的 对齐 方式。

<table width="400px" align="center">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商1班</td>
        <td>张三</td>
        <td>85</td>
    </tr>
</table>
<br /><br />
<table width="40%" align="right">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商2班</td>
        <td>李四</td>
        <td>90</td>
    </tr>
</table>

2.7.1.2. 边框与边框颜色

并不是所有表格化数据(tabular data)在显示时都带有表格线,上面的表格在网页上显示时就没有边框。可以使用 border 属性为表格指定以像素为单位的边框宽度,同时有些浏览器中还可以使用 bordercolor 属性指定边框颜色,后者没有出现在 HTML 4.01 的规范中,如:

<table border="1" bordercolor="#800">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商2班</td>
        <td>李四</td>
        <td>90</td>
    </tr>
</table>
<br /><br />
<table border="2" bordercolor="red">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商3班</td>
        <td>王五</td>
        <td>80</td>
    </tr>
</table>

观察上面的两个表格,注意我们目前设置的只是整个表格容器的 table 元素的边框宽度和颜色,即效果主要影响的是表格所占范围四周的那四条边框;同时,一旦进行此项设置,可以发现,作为单元格的 td 元素也自动具备了 1px 的相同颜色边框。另外,一个问题是即使表格边框设置值是 1px,我们发现其四条边框的宽度也不是排版时常用的最细的那种 1px 边框,这个问题将在 CSS 相关章节中解决。

bordercolor 属性对于边框颜色的设定在有些浏览器中没有效果或者效果和其它浏览器有差异,如 Internet Explorer 的较高版本。另外,除了 bordercolor 之外,在某些 浏览器中还可以结合使用 bordercolorlightbordercolordark 两个属性指定边框及边框内、外侧的颜色 对比以使得表格边框呈现凸出或凹陷的立体效果,使用较少,不过多描述。

对于表格及其单元格边框,table 元素还有两个属性 framerules,分别用于指定如何显示表格的 外部框架边框内部标尺线,由于使用频率非常低,此处也不过多描述。

2.7.1.3. 背景颜色与背景图片

使用 bgcolorbackground 属性可以分别指定整个表格的 背景颜色background color)和 背景图片

背景颜色:<font color="#FF0000">#FF000</font>
<br />
背景图片:<img src="bg_table.png" alt="背景图片" />
<br /><br />
<table background="bg_table.png" bgcolor="#FF0000" border="1" width="300px">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商1班</td>
        <td>张三</td>
        <td>85</td>
    </tr>
    <tr>
        <td>电商2班</td>
        <td>李四</td>
        <td>90</td>
    </tr>
    <tr>
        <td>电商3班</td>
        <td>王五</td>
        <td>80</td>
    </tr>
</table>

如上所示,1)当同时指定背景颜色和背景图片时,除非图片本身存在透明的部分,否则背景颜色会因被背景图片覆盖而无法显示,实际应用中一般不同时指定背景颜色和背景图片;2)当背景图片的实际面积小于表格所占区域时,图片将进行 平铺(tile)而不是 拉伸(stretch);3)上例看起来像是使用一张完整的和表格宽高一致的图片作为背景,其实是一个较小的不会太影响页面载入速度的 无缝拼接图案(seamless tiling pattern)平铺而出的。

2.7.1.4. 单元格填充与间距

表格有两个属性和其所包含的单元格有关:

  • cellpadding:用于设定表格每个单元格中的内容距离该单元格边框的距离,即 单元格填充值
  • cellspacing:用于设定表格相邻单元格之间或者是靠近表格边框的单元格边框与表格边框之间的距离,即 单元格间距

这两个属性的属性值一般是以像素为单位的整数数值,如下图所示。

![表格的边框、填充及间距示意图](../images/table_cellpaddingspacing.png)

表格的边框、填充及间距示意图

如果您是在线浏览本书,可以在下面的示例中,单击表格上方的超级链接,使得表格的 border、cellpadding、cellspacing 的属性值增加或减少,观察这三个属性对于表格的影响。

2.7.1.5 表格摘要

表格作为一种可视化呈现方式,带来的好处是将结构化数据一目了然地呈现在浏览器中,表格中每行代表的一条相对完整的信息、每列数据之间的内在关联等,通过视觉传递到大脑中并得以理解。但是,表格对于需要借助屏幕阅读器[[1]](http://baike.baidu.com/view/1892958.htm)等辅助技术[[2]](http://www.w3school.com.cn/glossary/assistive-technology.asp)Assistive Technology)来获取网页内容的盲人或有阅读障碍的残障人士来说却会带来一定困扰:纯粹单元格数据的罗列不如成段的文本易于理解。

随着社会文明的进步,我们不仅提倡在日常生活中通过安装无障碍设施等方法关爱残障人士,而且作为网页设计人员,应该增强网页的可用性(accessibility)使得残障人士具有同等访问互联网的便利以避免“数字鸿沟”的出现。为此,万维网联盟在 2008 年推出了 Web内容无障碍指南的2.0版本Web Content Accessibility Guidelines 2.0)作为一个 web 无障碍访问的推荐标准,一些国家和地区甚至颁布了相关的法律法规明确规定网页符合可用性的具体要求,如美国508无障碍法案

对于表格来说,其 summary 属性即是无障碍 web 访问的一个具体体现。summary 属性用于指定表格的 摘要 信息。网页设计人员将能够反映表格概要内容的文本作为属性值指定给 summary 属性,该文本不会可视地显示在浏览器窗口中,只有那些可以“阅读”的浏览器在遇到该表格时,会首先阅读此概要文本,阅读障碍人士在听到相关信息后会在大脑中形成关于接下来表格的内容的大致印象。这样,在表格单元格中内容被依次读出后,根据预先的摘要提示,内容将更容易被阅读障碍人士所理解。

<table summary="表一、电子商务专业成绩单">
    <tr>
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr>
        <td>电商2班</td>
        <td>李四</td>
        <td>90</td>
    </tr>
</table>

2.7.2. tr

作为行的 tr 元素,主要作用是包含并组织单元格 td 元素。作为单元格的容器,tr 元素的大部分属性会应用在该行内的所有 td 元素上。

2.7.2.1. 行高

可以使用 height 属性指定行的 高度,其属性值是一个以像素为单位的数值。

<table border="1">
    <tr height="32">
        <td>班级</td>
        <td>姓名</td>
        <td>成绩</td>
    </tr>
    <tr height="24px">
        <td>电商1班</td>
        <td>张三</td>
        <td>85</td>
    </tr>
</table>

table 不需要设置高度(没有 height 属性),tr 不需要指定宽度(没有 width 属性)。因为,逻辑上,表格由行直接构成,一旦确定表格宽度,行宽度即自动确定,而一旦确定所有行的高度,表格的高度也随之确定。

2.7.2.2. 对齐

可以使用 alignvalign 属性设置行的 水平对齐方式alignment)和 竖直对齐方式vertical alignment)。align 属性的属性值和之前介绍过的 p 元素基本一致[[3]](http://krijnhoetmer.nl/stuff/javascript/table-align-char/);valign 属性的属性值有常见的 top(顶端对齐)、middle(居中对齐)和 bottom(底部对齐),以及一个在纯中文排版中不是常用的 baseline(基线 对齐),middle 是竖直对齐的默认值。

由于 tr 元素只作为容器直接包含 td 元素,tr 不直接包含表格数据,表格数据只应该出现在 tr 所包含的 td 元素中,所以,就像前面提到的那样, tr 元素的对齐方式的设定其实是一次性指定了该行所有单元格中数据的对齐方式。

<table width="120">
    <tr height="64px" align="right" valign="bottom">
        <td>1</td>
        <td>2</td>
    </tr>
</table>

2.7.2.3. 背景与边框颜色

即使已经为整个表格指定过背景颜色(或图片)和边框颜色,依然可以通过为 tr 元素指定 bgcolor 和 bordercolor 来单独指定表格中某行的背景与边框颜色。

<table width="120" bgcolor="#CCFF99" border="1">
    <tr bgcolor="#FFFFCC" bordercolor="red">
        <td>1</td>
        <td>2</td>
    </tr>
    <tr>
        <td>3</td>
        <td>4</td>
    </tr>
    <tr bgcolor="#CCCCFF" bordercolor="blue">
        <td>5</td>
        <td>6</td>
    </tr>
</table>

下面是关于 tr 元素的一个综合示例:

2.7.3. td

表格中真正的数据容器是单元格 td。在介绍其它表格相关元素之前,可以认为,table 只能包含 tr,tr 只能包含 td,即 table、tr 均为 td 服务。所以,大部分针对 table、tr 的属性均可以直接针对表格中的某一单元格单独进行指定,这些属性有:width、height、align、valign、background、bgcolor、bordercolor,它们的具体设置方法不再赘述。

需要补充说明一下 width 属性:如果对于整个表格所有单元格的内容非常确定,如单元格中的内容较短不需要自动换行,此时可以不使用 width 属性手动指定而让浏览器自动确定根据内容自动确定表格、单元格的宽度;但是,一般情况下,为了排版的需要,我们一般为 table 指定 width 属性,然后为表格第一行(第 1 个 tr 元素)的 n 个单元格中的 n - 1 个单元格指定 width 属性,这样,最后一个(第 n 个)单元格的宽度会自动计算出来,同时由于第一行的所有单元格宽度的确定使得表格所有列的宽度被确定出来,其它行的单元格自动使用所在列宽的设置。

2.7.3.1. nowrap属性

nowrap 属性可以使得单元格内容在超出单元格宽度时 不自动换行。很明显,no- 为前缀的该属性表示一种判断,即这是一个布尔属性。

<table>
    <tr>
        <td width="20" nowrap="nowrap">单元格内容超过了 20 px</td>
    </tr>
</table>

既然存在这个属性,说明默认情况下,内容超出单元格宽度时会自动换行,这种默认模式使得我们可以相对精确地控制表格的列宽。当然,也存在例外,例如一个中间不存在连字符连续出现的英文字母(比如一个较长的英文单词),如果其实际宽度已经超过一个单元格的宽度,那么即使为该单元格不指定 nowrap 属性,这些连续出现的英文字母一定不会自动换行。

<table>
    <tr>
        <td width="20">
            pneumonoultramicroscopicsilicovolcanoconiosis
            is a kind of diseases.
        </td>
    </tr>
</table>

上例中,单元格的实际的宽度应该和单元格中那个最长的单词[[4]](http://zh.wikipedia.org/wiki/%E6%9C%80%E9%95%BF%E7%9A%84%E8%8B%B1%E6%96%87%E5%8D%95%E8%AF%8D)的实际宽度大致相似,而不是该单元格宽度的设定值。

2.7.3.2. 单元格合并

单元格合并是表格中经常用到的操作。

如在 Microsoft Word 中,我们一般是将光标定位到表格的某一单元格中,然后按下鼠标左键,向水平方向或竖直方向进行拖拽以选中连续多个单元格,然后使用菜单项或者工具栏按钮中的“合并单元格”命令将这些单元格合并成一个大的单元格。

和上面的操作过程相似,HTML 中单元格合并要首先确定一个起始单元格,这个单元格应该是待合并的连续多个单元格中行序号和列序号均最小的那一个 td 元素。接下来,为该 td 元素指定 rowspan 和 colspan 属性,span 指跨度,rowspan 即指从起始单元格开始竖直方向上要 合并的行数row span),colspan 则指水平方向上要 合并的列数column span)。

如,在一个 4*5 的表格中,要将第 2 行第 2 列一直到第 3 行第 4 列的 6 个单元格合并在一起,该表格的结构会变成:

<table border="1" width="500">
    <tr>
        <td>1 , 1</td>
        <td>1 , 2</td>
        <td>1 , 3</td>
        <td>1 , 4</td>
        <td>1 , 5</td>
    </tr>
    <tr>
        <td>2 , 1</td>
        <td colspan="3" rowspan="2" bgcolor="silver">2 , 2</td>
        <td>2 , 5</td>
    </tr>
    <tr>
        <td>3 , 1</td>
        <td>3 , 5</td>
    </tr>
    <tr>
        <td>4 , 1</td>
        <td>4 , 2</td>
        <td>4 , 3</td>
        <td>4 , 4</td>
        <td>4 , 5</td>
    </tr>
</table>

仔细观察上面的代码,我们发现,在进行单元格合并后,整个表格的 td 元素的数量比合并前减少了。所以,在单元格合并时,不仅要正确设置起始 td 元素的 rowspan 和 colspan 属性值,而且要注意起始单元格所在行的 tr 元素甚至是紧接在其后的多个 tr 元素中 td 元素的数量如何变化。

对于表格来说,td 元素才是真正表格数据的容器,其它相关元素(table、tr 等)都是该元素的辅助元素。

几乎任何内联和区块元素都可以直接包含在一个 td 元素中成为单元格的内容。

单元格的这种特性导致早期的一些网页中经常使用表格来作为页面布局的工具。“布局” 是一个围棋术语,在页面上不同位置排列不同元素很像在围棋棋盘上放置黑白子的过程。比如,由于段落是区块元素,顺序出现的 p 元素都会创建新行,如果我们希望在网页中将两个不同的段落并排在一行显示,目前可以想到的方法是将这两个段落放在表格一行中的两个单元格里。按照这种逻辑,早期的网页通常在 body 元素里直接包含一个 table 元素,使用该表格的单元格将页面划分成不同的区域以搭建整体页面的架构,剩下的工作就是在单元格中填充不同的内容。有时为了达到某种效果,单元格中需要再嵌套另外的子表格,最终导致页面灵活性很差,代码也显得繁琐。所以,尽管表格可以用来作为布局工具,但是这并不是表格正确的用途,表格应该只用来展现那些适合表格化显示的信息。

2.7.4. 表格相关的其它元素

除了 table、tr、td 三个必要元素之外,HTML 在创建表格时还有一些其它辅助性元素。

2.7.4.1. th

th 用于定义表格内部的 表头table header)单元格。

在一些表格中,如果为了强调表格的前 m 行、前 n 列,网页设计人员会把它们定义为表头单元格,此时只需要把前 m 个 tr 元素的所有 td 元素以及其它每个 tr 元素中的前 n 个 td 元素的元素名由 td 替换为 th 即可,如:

<table border="1" bordercolor="#800">
    <tr>
        <th>班级</th>
        <th>姓名</th>
        <th>成绩</th>
    </tr>
    <tr>
        <th>电商2班</th>
        <td>李四</td>
        <td>90</td>
    </tr>
</table>

th 元素内部的文本通常会呈现为居中的粗体文本,而 td 元素内的文本通常是左对齐的普通文本。

相对于被称为表头单元格的 th 来说,td 也被称为 标准单元格。th 元素应该出现的位置及支持的属性和 td 元素基本一致。

2.7.4.2. caption

caption 元素用于为表格指定 标题 作为表格的说明性文字,该元素应该紧随 table 元素的开始标签之后直接包含在 table 元素之内,每个 table 元素中只能指定一个标题。

标题将默认显示在表格上方正中位置。虽然 caption 元素紧跟 table 元素在所有 tr、td 元素之前,但依然可以通过指定其 align 属性值为 bottom 使得标题显示在更为常见的表格下部正中位置。align 属性的属性值还可以是 left、right 以使得标题显示在表格的左侧和右侧,但主流浏览器的较新版本除了 Firefox 之外并不能很好地支持该设置。

2.7.4.3. thead、tbody 和 tfoot

theadtbody 以及 tfoot 元素用于对表格中的行进行分组,使得它们成为 表格题头table head)、表格主体table body)、表格脚注table foot)的一部分。比如,在某些浏览器中,也许希望拥有一个标题行,一些带有数据的行,以及位于底部的一个总计行。这种划分使浏览器有能力支持独立于表格标题和页脚的表格正文滚动;当长的表格被打印时,表格的表头和页脚可被打印在包含表格数据的每张页面上。

<table>
    <caption align="bottom">表1 电子商务系成绩单</caption>
    <thead>
        <tr>
            <th>班级</th>
            <th>姓名</th>
            <th>成绩</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>电商1班</td>
            <td>张三</td>
            <td>85</td>
        </tr>
        <tr>
            <td>电商2班</td>
            <td>李四</td>
            <td>90</td>
        </tr>
        <tr>
            <td>电商3班</td>
            <td>王五</td>
            <td>80</td>
        </tr>
    </tbody>
    <tfoot>
        <tr>
            <td colspan="2">平均分: </td>
            <td>85</td>
        </tr>
    </tfoot>
</table>

2.7.4.4. colgroup 和 col

行可以分组,HTML 描述表格时虽然绕开了列的概念,但逻辑上的列还是存在的,而且 HTML 允许我们对逻辑上的列进行分组,即使用 colgroup 元素创建 列组column group)。创建列组的作用是对该列组中的列(逻辑上)所包含的单元格应用相同的设置(width、bgcolor 等属性),如:

<table border="1">
    <colgroup span="2"></colgroup>
    <colgroup span="4" width="32"></colgroup>
    <tr>
        <td>1,1</td>
        <td>1,2</td>
        <td>1,3</td>
        <td>1,4</td>
        <td>1,5</td>
        <td>1,6</td>
    </tr>
    <tr>
        <td>2,1</td>
        <td>2,2</td>
        <td>2,3</td>
        <td>2,4</td>
        <td>2,5</td>
        <td>2,6</td>
    </tr>
</table>

上例在 table 元素中创建了两个列组,它们的 跨度span)分别是 2 和 4,即两个列组覆盖了表格的所有 6 列。其中,前两列中所有单元格中的内容都是居中显示的,后四列的宽度都是 32px。想象一下不使用列组元素呈现同样的一个表格,很容易发现,列组的使用可以避免重复设置属性帮助简化 HTML 代码。

指定了 span 属性大于 1 的 colgroup 中还可以嵌套 col 元素,进一步指定该列组中每一列所属单元格的共同属性,如:

<table border="1">
    <colgroup span="2" width="60">
        <col bgcolor="silver" width="80" />
        <col bgcolor="gray" />
    </colgroup>
    <colgroup span="4" width="32"></colgroup>
    <tr>
        <td>1,1</td>
        <td>1,2</td>
        <td>1,3</td>
        <td>1,4</td>
        <td>1,5</td>
        <td>1,6</td>
    </tr>
    <tr>
        <td>2,1</td>
        <td>2,2</td>
        <td>2,3</td>
        <td>2,4</td>
        <td>2,5</td>
        <td>2,6</td>
    </tr>
</table>

col 元素是一个空元素,不包含任何内容,它的属性和 colgroup 一致。如果 col 元素指定了和其所在 colgroup 元素相同的属性,col 元素中该属性的属性值将覆盖 colgroup 中的属性设置,如上例中第一列中单元格宽度将为 80px 而不是 60px。

col 元素也可以脱离 colgroup 元素单独包含在 table 元素中,甚至可以为其指定 span 属性实现和 colgroup 元素类似的一次指定多列单元格共同属性的效果。

多达 10 个相关元素使得表格成为 HTML 中最为复杂的结构,下面是使用了所有相关元素的一个综合应用实例:

<table border="1" cellspacing="1" cellpadding="2">
    <caption align="bottom">表一、电子商务专业期末成绩单</caption>
    <colgroup span="3">
        <col width="60" />
        <col width="100" />
        <col width="80" bgcolor="skyblue" />
    </colgroup>
    <col span="3" width="120" />
    <thead>
        <tr>
            <th rowspan="2">班级</th>
            <th rowspan="2">学号</th>
            <th rowspan="2" bgcolor="white">姓名</th>
            <th colspan="3">成绩</th>
        </tr>
        <tr>
            <th>高等数学</th>
            <th>大学英语</th>
            <th>计算机基础</th>
        </tr>
    </thead>
    <tfoot>
        <tr>
            <th colspan="3">平均分:</th>
            <th>83.33</th>
            <th>80</th>
            <th>88.33</th>
        </tr>
    </tfoot>
    <tbody>
        <tr>
            <td>1 班</td>
            <td>00001</td>
            <td>张三</td>
            <td>80</td>
            <td>85</td>
            <td>90</td>
        </tr>
        <tr>
            <td>2 班</td>
            <td>00002</td>
            <td>李四</td>
            <td>100</td>
            <td>90</td>
            <td>85</td>
        </tr>
        <tr bgcolor="silver" bordercolor="silver">
            <td>3 班</td>
            <td>00003</td>
            <td>王五</td>
            <td>70</td>
            <td>65</td>
            <td>90</td>
        </tr>
    </tbody>
</table>