17 表格

内容

注意:本规范的若干章节已被其他规范更新。请参阅最新 CSS Snapshot 中的 “层叠样式表 (CSS) — 官方定义”,其中列出了规范以及它们取代的章节。

CSS 工作组也在开发 CSS 2 级修订版 2(CSS 2.2)

17.1 表格简介

本章定义了 CSS 中表格的处理模型。其中一部分是布局。关于布局,本章介绍了两种算法;第一种,固定表格布局算法,定义明确;第二种,自动表格布局算法,则未在本规范中完整定义。

对于自动表格布局算法,一些部署广泛的实现已经达到了相对接近的互操作性。

表格布局可用于表示数据之间的表格关系。作者在文档语言中指定这些关系,并可使用 CSS 2.1 指定它们的呈现方式

在视觉媒介中,CSS 表格也可用于实现特定的布局。在这种情况下,作者不应在文档语言中使用与表格相关的元素,而应将 CSS 应用于相关的结构元素,以实现期望的布局。

作者可以将表格的视觉格式指定为矩形网格的单元格。行和列的单元格可以组织成行组和列组。行、列、行组、列组以及单元格都可以在其周围绘制边框(CSS 2.1 中有两种边框模型)。作者可以在单元格内垂直或水平对齐数据,并在整行或整列的所有单元格中对齐数据。

示例

下面是一个用 HTML 4 描述的简单三行三列表格示例

<TABLE>
<CAPTION>This is a simple 3x3 table</CAPTION>
<TR id="row1">
   <TH>Header 1  <TD>Cell 1  <TD>Cell 2
<TR id="row2">
   <TH>Header 2  <TD>Cell 3  <TD>Cell 4
<TR id="row3">
   <TH>Header 3  <TD>Cell 5  <TD>Cell 6
</TABLE>

这段代码创建了一个表格(TABLE 元素),三行(TR 元素),三个表头单元格(TH 元素),以及六个数据单元格(TD 元素)。请注意,此示例的三列是隐式指定的:表格的列数由表头和数据单元格的需要决定。

下面的 CSS 规则将表头单元格中的文本水平居中,并将其呈现为粗体字重

th { text-align: center; font-weight: bold }

接下来的规则使表头单元格的文本在基线上对齐,并在每个数据单元格中垂直居中该文本

th { vertical-align: baseline }
td { vertical-align: middle }

接下来的规则规定顶行将被 3px 实线蓝色边框包围,而其它行将被 1px 实线黑色边框包围

table   { border-collapse: collapse }
tr#row1 { border: 3px solid blue }
tr#row2 { border: 1px solid black }
tr#row3 { border: 1px solid black }

但请注意,行之间的边框会在相交处重叠。行 1 与行 2 之间的边框到底是黑色还是蓝色,宽度是 1px 还是 3px?我们将在边框冲突解决一节中讨论此问题。

下面的规则将表格标题置于表格之上

caption { caption-side: top }

前面的示例展示了 CSS 如何配合 HTML 4 元素使用;在 HTML 4 中,各种表格元素(TABLE、CAPTION、THEAD、TBODY、TFOOT、COL、COLGROUP、TH 和 TD)的语义已被明确定义。在其他文档语言(例如 XML 应用)中,可能没有预定义的表格元素。因此,CSS 2.1 允许作者通过'display'属性“映射”文档语言元素到表格元素。例如,下面的规则使 FOO 元素表现得像 HTML 的 TABLE 元素,BAR 元素表现得像 CAPTION 元素

FOO { display : table }
BAR { display : table-caption }

我们将在下节讨论各种表格元素。在本规范中,表格元素指任何参与创建表格的元素。内部表格元素是指生成行、行组、列、列组或单元格的元素。

17.2 CSS 表格模型

CSS 表格模型基于 HTML 4 表格模型,其中表格的结构与其视觉布局紧密对应。在此模型中,表格由一个可选的标题以及任意数量的单元格行组成。该模型被称为“行主导”,因为作者在文档语言中显式指定行,而不是列。列在所有行都已指定后才得以推导——每行的第一个单元格属于第一列,第二个单元格属于第二列,依此类推)。行和列可以在结构上进行分组,并在呈现时体现这种分组(例如,可在一组行周围绘制边框)。

因此,表格模型包括表格、标题、行、行组(包括表头组和表脚组)、列、列组和单元格。

CSS 模型并不要求文档语言必须包含对应于这些组件的元素。对于没有预定义表格元素的文档语言(如 XML 应用),作者必须将文档语言元素映射到表格元素;这通过'display'属性实现。下面的'display'取值将任意元素指派表格格式规则

table(在 HTML 中对应:TABLE)
指定元素定义一个块级表格:它是一个参与块格式化上下文的矩形块。
inline-table(在 HTML 中对应:TABLE)
指定元素定义一个行内级表格:它是一个参与行内格式化上下文的矩形块。
table-row(在 HTML 中对应:TR)
指定元素是一个单元格行。
table-row-group(在 HTML 中对应:TBODY)
指定元素将一个或多个行分组。
table-header-group(在 HTML 中对应:THEAD)
与'table-row-group'相同,但在视觉格式化时,行组始终在所有其它行和行组之前显示,并且在任何顶部标题之后显示。打印用户代理可以在表格跨页的每一页上重复表头行。如果表格中包含多个带有'display: table-header-group'的元素,则仅第一个会渲染为表头;其余的将被视为带有'display: table-row-group'。
table-footer-group(在 HTML 中对应:TFOOT)
与'table-row-group'相同,但在视觉格式化时,行组始终在所有其它行和行组之后显示,并且在任何底部标题之前显示。打印用户代理可以在表格跨页的每一页上重复表脚行。如果表格中包含多个带有'display: table-footer-group'的元素,则仅第一个会渲染为表脚;其余的将被视为带有'display: table-row-group'。
table-column(在 HTML 中对应:COL)
指定元素描述了一个单元格列。
table-column-group(在 HTML 中对应:COLGROUP)
指定元素将一个或多个列进行分组。
table-cell(在 HTML 中对应:TD、TH)
指定元素代表一个表格单元格。
table-caption(在 HTML 中对应:CAPTION)
为表格指定标题。所有带有'display: table-caption'的元素都必须渲染,详见第 17.4 节

具有这些'display'取值的替换元素在布局期间被视为其对应的显示类型。例如,设为'display: table-cell'的图像会填充可用的单元格空间,并且其尺寸会像普通单元格一样参与表格尺寸算法。

'display'设为'table-column'或'table-column-group'的元素不渲染(等同于'display: none'),但它们仍有用,因为它们可以拥有属性,从而为它们所代表的列产生特定的样式。

附录中的HTML 4 默认样式表演示了这些取值在 HTML 4 中的使用方式。

table    { display: table }
tr       { display: table-row }
thead    { display: table-header-group }
tbody    { display: table-row-group }
tfoot    { display: table-footer-group }
col      { display: table-column }
colgroup { display: table-column-group }
td, th   { display: table-cell }
caption  { display: table-caption }

用户代理可以忽略这些'display'属性值,以便对 HTML 表格使用其他为向后兼容而设计的渲染算法。不过,这并不意味着不应在 HTML 的非表格元素上使用'display: table'。

17.2.1 匿名表格对象

除 HTML 外的文档语言可能不包含 CSS 2.1 表格模型中的全部元素。在这种情况下,必须假设“缺失”的元素,以使表格模型能够工作。任何表格元素都会自动在自身周围生成必要的匿名表格对象,至少包含三个嵌套对象,分别对应 'table'/'inline-table'、'table-row' 和 'table-cell'。缺失的元素会依据以下规则生成匿名对象(例如,可视表格布局中的匿名盒子)。

为阐述这些规则,以下术语被定义:

行组盒子
'table-row-group'、'table-header-group' 或 'table-footer-group'
正确的表格子元素
'table-row' 盒、行组盒、'table-column' 盒、'table-column-group' 盒或 'table-caption' 盒。
正确的表格行父元素
'table' 或 'inline-table' 盒或行组盒。
内部表格盒子
'table-cell' 盒、'table-row' 盒、行组盒、'table-column' 盒或 'table-column-group' 盒。
表格容器 (tabular container)
'table-row' 盒或正规表格行父元素。
连续的
如果两个同级盒子中间没有其他同级盒子(除了可能存在的仅包含空格的匿名行内盒子),则它们是连续的。如果序列中的每个盒子都与其序列中的前一个盒子连续,则一系列同级盒子是连续的。

在这些规则中,脱离流的元素被视为宽高均为零的行内元素。其包含块相应选取。

以下步骤分三阶段执行。

  1. 移除无关的盒子
    1. 所有 'table-column' 父元素的子盒都视作具有 'display: none'。
    2. 如果 'table-column-group' 父元素的子 C 不是 'table-column' 盒,则视作具有 'display: none'。
    3. 如果表格容器 P 的子 C 是仅包含空白的匿名行内盒,并且其前后兄弟(若存在)都是 P 的正规表格后代且为 'table-caption' 或内部表格盒,则视作具有 'display: none'。若 D 可以成为 A 的后代而不导致生成任何中间的 'table' 或 'inline-table' 盒,则称 DA 的正规表格后代。
    4. 如果匿名行内盒 B 仅包含空白且位于两个相邻兄弟之间,而这两个兄弟每个都是内部表格盒或 'table-caption' 盒,则 B 视作具有 'display: none'。
  2. 生成缺失的子包装器
    1. 如果 'table' 或 'inline-table' 盒的子 C 不是正规表格子元素,则在 C 及其所有连续的非正规表格子兄弟周围生成匿名 'table-row' 盒。
    2. 如果行组盒的子 C 不是 'table-row' 盒,则在 C 及其所有连续的非 'table-row' 兄弟周围生成匿名 'table-row' 盒。
    3. 如果 'table-row' 盒的子 C 不是 'table-cell',则在 C 及其所有连续的非 'table-cell' 兄弟周围生成匿名 'table-cell' 盒。
  3. 生成缺失的父级
    1. 对连续的内部表格和 'table-caption' 兄弟中的每个 'table-cell' 盒 C,若其父不是 'table-row',则在 C 及其所有连续的 'table-cell' 兄弟周围生成匿名 'table-row' 盒。
    2. 对连续的正规表格子元素序列中的每个正规表格子 C,若其父级不正确,则在 C 及其所有连续的正规表格子兄弟周围生成匿名 'table' 或 'inline-table' 盒 T。(如果 C 的父是行内盒,则 T 必须是 'inline-table' 盒;否则必须是 'table' 盒。)
      • 'table-row' 若其父既不是行组盒也不是 'table' 或 'inline-table' 盒,则称为错误父级。
      • 'table-column' 盒若其父既不是 'table-column-group' 盒也不是 'table' 或 'inline-table' 盒,则称为错误父级。
      • 行组盒、'table-column-group' 盒或 'table-caption' 盒若其父既不是 'table' 盒也不是 'inline-table' 盒,则称为错误父级。

示例

在下面的 XML 示例中,假设 'table' 元素包含 HBOX 元素

<HBOX>
  <VBOX>George</VBOX>
  <VBOX>4287</VBOX>
  <VBOX>1998</VBOX>
</HBOX>

因为关联的样式表是:

HBOX { display: table-row }
VBOX { display: table-cell }

示例

在此示例中,假设三个 'table-cell' 元素包含 ROW 中的文本。注意,文本进一步被封装在匿名行内盒中,详见可视格式化模型

<STACK>
  <ROW>This is the <D>top</D> row.</ROW>
  <ROW>This is the <D>middle</D> row.</ROW>
  <ROW>This is the <D>bottom</D> row.</ROW>
</STACK>

样式表如下

STACK { display: inline-table }
ROW   { display: table-row }
D     { display: inline; font-weight: bolder }

17.3

表格单元格可能属于两个上下文:行和列。然而,在源文档中,单元格是行的后代,绝不会是列的后代。尽管如此,某些单元格属性仍可通过在列上设置属性来影响。

以下属性适用于列和列组元素:

'border'
只有当表格元素的'border-collapse' 被设为 'collapse' 时,边框属性才会作用于列。此时,列和列组上的边框会作为输入参与冲突解决算法,从而决定每个单元格边缘的边框样式。
'background'
背景属性为列中的单元格设置背景,但仅在单元格和所在行的背景均为透明时生效。参见“表格层与透明度”
'width'
'width'属性为列提供最小宽度。
'visibility'
如果列的 'visibility' 被设为 'collapse',则该列的所有单元格都不渲染,跨列的单元格会被裁剪。同时,表格的宽度会相应减去该列原本占用的宽度。参见下文的“动态效果”。'visibility' 的其它取值不产生影响。

示例

下面给出一些在列上设置属性的示例规则。前两条规则一起实现 HTML 4 中值为“cols”的“rules”属性。第三条规则将 “totals” 列设为蓝色,最后两条规则展示了如何使用固定布局算法将列设为固定大小。

col { border-style: none solid }
table { border-style: hidden }
col.totals { background: blue }
table { table-layout: fixed }
col.totals { width: 5em }

17.4 可视格式化模型中的表格

从可视格式化模型的角度看,表格可以表现为块级(对应 'display: table')或行内级(对应 'display: inline-table')元素。

无论哪种情况,表格都会生成一个称为表格包装盒的主块盒,内部包含表格盒本身以及所有标题盒(按照文档顺序)。表格盒是一个块级盒,容纳表格的内部表格盒。标题盒是块级盒,保留各自的内容、内边距、外边距和边框区,并作为普通块盒渲染在表格包装盒内部。标题盒是放在表格盒之前还是之后,由'caption-side'属性决定,详见下文。

如果表格是块级的,表格包装盒为 'block' 盒;如果表格是行内级的,则为 'inline-block' 盒。表格包装盒建立块格式化上下文。对于 'inline-table',进行基线垂直对齐时使用的是表格盒(而非表格包装盒)。表格包装盒的宽度等同于其内部表格盒的边框边缘宽度,详见第 17.5.2 节。表格的 'width' 与 'height' 的百分比相对于表格包装盒的包含块,而不是相对于表格包装盒本身。

表格元素的 'position'、'float'、'margin-*'、'top'、'right'、'bottom' 和 'left' 的计算值用于表格包装盒,而非表格盒;其余不可继承属性的计算值用于表格盒,而非表格包装盒。(若表格元素的这些值未被表格及表格包装盒使用,则使用初始值。)

A table with a caption above
it

带标题的表格图示。

17.4.1 标题位置与对齐

'caption-side'
  top | bottom | inherit
初始值  top
应用于  ‘table-caption’ 元素
可继承  
百分比  不适用
媒体  视觉
计算值  按指定值

此属性指定标题盒相对于表格盒的位置。各取值含义如下:

top
将标题框定位在表格框上方。
bottom
将标题框定位在表格框下方。

注意:CSS2 对宽度和水平对齐的行为有不同的描述。该行为将在 CSS3 中通过本属性的 'top-outside' 与 'bottom-outside' 取值引入。

若要在标题盒内部水平对齐标题内容,请使用'text-align'属性。

示例

在下面的例子中,'caption-side'属性将标题放在表格下方。标题的宽度将与表格的父元素宽度相同,标题文本左对齐。

caption { caption-side: bottom; 
          width: auto;
          text-align: left }

17.5 表格内容的可视布局

内部表格元素会生成带有内容和边框的矩形盒子。单元格还有内边距。内部表格元素没有外边距。

这些盒子的可视布局受一组矩形、不规则的行列网格支配。每个盒子占据若干网格单元格,具体规则如下。这些规则不适用于 HTML 4 及更早的 HTML 版本;HTML 对跨行跨列有其自己的限制。

  1. 每个行盒占据一行网格单元格。所有行盒按它们在源文档中出现的顺序自上而下填充表格(即表格的网格行数恰好等于行元素的数量)。
  2. 行组占据它所包含的行相同的网格单元格。
  3. 列盒占据一个或多个列的网格单元格。列盒按出现顺序并排放置。首列盒位于左侧还是右侧取决于表格的'direction'属性值。
  4. 列组盒占据它所包含的列相同的网格单元格。
  5. 单元格可以跨越多行或多列。(虽然 CSS 2.1 未定义跨越的行列数如何确定,用户代理可以对源文档拥有特殊认知;未来的 CSS 更新可能提供在 CSS 语法中表达此认知的方法。)因此,每个单元格都是一个矩形盒子,宽高均为若干网格单元格。该矩形的顶部行位于单元格父元素所指定的行。矩形应尽可能靠左放置,但其占据的第一列必须不与任何其他单元格盒(例如,先前行的跨行单元格)重叠,并且该单元格必须位于同一行中在源文档中更早的所有单元格的右侧。如果该位置会导致跨列单元格与先前行的跨行单元格重叠,CSS 并未定义结果:实现可以选择让单元格重叠(如多数 HTML 实现所为),或将后面的单元格向右移动以避免重叠。(如果表格的 'direction' 为 'ltr',上述描述成立;若为 'rtl',则将 “左” 与 “右” 互换。)
  6. 单元格盒不能延伸超出表格或行组的最后一个行盒;用户代理必须将其缩短直至合适。

折叠边框模型中,行、列、行组和列组的边缘与假想的网格线重合,单元格边框正好居中于这些线。(因此在此模型中,行完整覆盖表格而不留空隙;列亦同。)在分离边框模型中,边缘与单元格的边框边缘重合。(因此在此模型中,行、列、行组或列组之间可能出现空隙,对应于'border-spacing'属性的值。)

注意。对表格单元格进行定位或浮动可能导致它们不再是表格单元格,依据第 9.7 节的规则。当使用浮动时,匿名表格对象的规则可能会导致创建匿名单元格对象。

下面是一个演示规则 5 的例子。以下非法 (X)HTML 片段定义了冲突的单元格。

<table>
<tr><td>1 </td><td rowspan="2">2 </td><td>3 </td><td>4 </td></tr>
<tr><td colspan="2">5 </td></tr>
</table>

用户代理可以自由选择将单元格视觉上重叠(如左图),或将单元格移动以避免视觉重叠(如右图)。

一个表格中有重叠单元格和一个没有重叠单元格的示例   [D]

错误 HTML 表格的两种可能渲染方式。

17.5.1 表格层与透明度

为寻找每个表格单元格的背景,六个叠加层可以用来思考不同表格元素的背景。位于某一层的元素背景仅在其上方层的背景均为透明时才可见。

表格层的示意图   [D]

表格层图示。

  1. 最低层是一平面,代表表格盒本身。和所有盒一样,它可以是透明的。
  2. 下一层包含列组。每个列组的范围从顶部行的单元格顶部一直到底部行的单元格底部,且从最左侧列的左边缘延伸到最右侧列的右边缘。其背景恰好覆盖所有起源于该列组的单元格的完整区域,即便这些单元格跨出列组范围,这一面积差异不影响背景图像的定位。
  3. 在列组之上是表示列盒的区域。每列的高度与列组相同,宽度等同于该列中普通(单列跨越)单元格的宽度。背景同样恰好覆盖所有起源于该列的单元格的完整区域,即便这些单元格跨出列范围,面积差异同样不影响背景图像定位。
  4. 接下来是包含行组的层。每个行组的范围从其第一列中最顶部单元格的左上角延伸到其最后一列中最底部单元格的右下角。
  5. 倒数第二层包含行。每行的宽度与行组相同,高度与该行中普通(单行跨越)单元格的高度相同。与列类似,背景恰好覆盖所有起源于该行的单元格的完整区域,即便这些单元格跨出行范围,面积差异不影响背景图像定位。
  6. 最上层包含单元格本身。如图所示,尽管所有行包含相同数量的单元格,但并非每个单元格都必须有内容。在分离边框模型'border-collapse' 为 'separate')中,如果它们的'empty-cells'属性值为 'hide',这些“空”单元格会在单元格、行、行组、列和列组背景之上保持透明,从而显示表格背景。

“缺失单元格”指网格中未被元素或伪元素占据的单元格。缺失单元格会被渲染为如果有一个匿名 table-cell 盒占据它们在网格中的位置。

在下面的示例中,第一行有四个非空单元格,而第二行仅有一个非空单元格,因此表格背景会显示出来,只是第一行跨入第二行的单元格所在位置会遮挡背景。下面的 HTML 代码与样式规则

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>Table example</TITLE>
    <STYLE type="text/css">
      TABLE  { background: #ff0; border: solid black;
               empty-cells: hide }
      TR.top { background: red }
      TD     { border: solid black }
    </STYLE>
  </HEAD>
  <BODY>
    <TABLE>
      <TR CLASS="top">
        <TD> 1 
        <TD rowspan="2"> 2
        <TD> 3 
        <TD> 4 
      <TR>
        <TD> 5
        <TD>
    </TABLE> 
  </BODY>
</HTML>

可能呈现如下:

底部行中有三个空单元格的表格示例   [D]

底部行有空单元格的表格。

请注意,如果表格的 'border-collapse' 为 'separate',则由'border-spacing'属性给出的区域始终使用表格元素的背景。详见分离边框模型

17.5.2 表格宽度算法: 'table-layout'属性

CSS 并未为表格定义“最优”布局,因为在很多情况下,何为最优取决于个人品味。CSS 确实定义了用户代理在布局表格时必须遵守的约束。用户代理可以自由选择任何算法来实现布局,并且可以在渲染速度与精确度之间做出取舍,除非选用了“固定布局算法”。

请注意,本节覆盖了在第 10.3 节中描述的宽度计算规则。特别是,如果表格的外边距被设为“0”,宽度设为“auto”,表格不会自动扩展以填满其包含块。然而,一旦表格的计算后宽度(使用下面的算法或在适当情况下使用其他 UA‑dependent 算法)被求得,10.3 节的其余部分仍然适用。因此,表格**可以**通过左、右外边距为“auto”来居中,例如。

未来的 CSS 更新可能会引入让表格自动适应其包含块的方式。

'table-layout'
  auto | fixed | inherit
初始值  auto
应用于  ‘table’ 和 ‘inline-table’ 元素
可继承  
百分比  不适用
媒体  视觉
计算值  按指定值

'table-layout'属性控制用于布局表格单元格、行和列的算法。取值含义如下:

fixed
使用固定表格布局算法
auto
使用任何自动表格布局算法

下面描述这两种算法。

17.5.2.1 固定表格布局

使用此(快速)算法时,表格的水平布局不依赖于单元格内容;仅依赖于表格宽度、列宽以及边框或单元格间距。

表格宽度可以通过'width'属性显式指定。'auto' 值(对 'display: table' 与 'display: inline-table' 均适用)表示使用自动表格布局算法。然而,如果表格是普通流中的块级表格('display: table'),用户代理可以(但不必)使用10.3.3 节的算法来计算宽度,并在指定宽度为 'auto' 时仍采用固定表格布局。

示例

如果 UA 在宽度为 'auto' 时仍支持固定表格布局,则下面的代码会创建一个比其包含块窄 4em 的表格:

table { table-layout: fixed;
        margin-left: 2em;
        margin-right: 2em }

在固定表格布局算法中,每列的宽度如下确定:

  1. 如果列元素的'width'属性值不是 'auto',则该值即为该列的宽度。
  2. 否则,第一行中具有非 'auto' 'width' 值的单元格决定该列宽度。如果该单元格跨越多列,则宽度会在这些列之间均分。
  3. 其余列等分剩余的水平表格空间(减去边框或单元格间距)。

表格的宽度随后取'width'属性值与所有列宽之和(加上单元格间距或边框)的较大者。如果表格宽度大于列宽之和,则多余空间应分配到各列。

如果随后的行包含的列数多于由表格列元素决定的列数或第一行决定的列数,则额外的列可能不会被渲染。CSS 2.1 并未定义如果这些列被渲染时的列宽和表格宽度。当使用 'table-layout: fixed' 时,作者不应在第一行中省略列。

通过这种方式,用户代理在收到完整的第一行后即可开始布局表格。随后的行中的单元格不会影响列宽。任何内容溢出的单元格会依据'overflow'属性决定是否裁剪溢出内容。

17.5.2.2 自动表格布局

该算法(通常只需两遍)使表格宽度由列宽(以及中间的边框)决定。该算法反映了本规范撰写时若干流行 HTML 用户代理的行为。UAs 并不必须实现此算法来决定当'table-layout' 为 'auto' 时的表格布局;它们可以使用任何其他算法,即便结果不同。

自动表格布局的输入仅包括包含块的宽度以及表格本身及其所有后代的内容和任何 CSS 属性。

注意。此内容可能在 CSS3 中得到更详细的定义。

本节其余部分是非规范性的。

该算法可能效率低下,因为它要求用户代理在确定最终布局之前能够访问表格中的全部内容,并且可能需要多次遍历。

列宽的确定方式如下

  1. 计算每个单元格的最小内容宽度 (MCW):格式化后的内容可以跨多行,但不能溢出单元格盒子。如果单元格指定的 'width' (W) 大于 MCW,则 W 为最小单元格宽度。取值为 'auto' 表示 MCW 即为最小单元格宽度。

    另外,计算每个单元格的“最大”宽度:在保持内容不换行(除非出现显式换行符)的情况下进行格式化。

  2. 对于每一列,从仅跨该列的单元格中确定最大列宽和最小列宽。最小列宽取决定于具有最大最小单元格宽度的单元格(或该列的 'width',两者取较大者)。最大列宽取决定于具有最大最大单元格宽度的单元格(或该列的 'width',两者取较大者)。

  3. 对于跨越多个列的每个单元格,增加其跨越列的最小宽度,使它们的总宽度至少与该单元格相等。最大宽度亦同。如果可能,尽量让所有跨越的列宽度以相近的幅度增大。

  4. 对于每个 width 取值非 'auto' 的列组元素,增大其跨越列的最小宽度,使它们的总宽度至少等于该列组的 width

这样便为每列得到一个最大宽度和最小宽度。

标题的最小宽度(CAPMIN)通过为每个标题计算最小标题外宽度来确定,该宽度等同于一个假想的表格单元格的 MCW,且该单元格的内容以 display: block 方式格式化。所有标题的最小外宽度中的最大值即为 CAPMIN。

列和标题的宽度对最终表格宽度的影响如下

  1. 如果 'table' 或 'inline-table' 元素的 'width' 属性的计算值 (W) 不是 'auto',则实际使用的宽度取 W、CAPMIN 以及所有列加上单元格间距或边框所需的最小宽度 (MIN) 三者中的最大值。如果实际使用宽度大于 MIN,则多余的宽度应在各列之间分配。
  2. 如果 'table' 或 'inline-table' 元素的 width 为 'auto',则实际使用宽度取表格所在包含块的宽度、CAPMIN 和 MIN 三者中的最大值。但如果 CAPMIN 或列加上单元格间距或边框所需的最大宽度 (MAX) 小于包含块的宽度,则使用 max(MAX, CAPMIN)。

列宽的百分比值相对于表格宽度。如果表格的 width 为 'auto',百分比表示对列宽的约束,用户代理应尽力满足。(显然,这并不总是可能的:如果列宽为 '110%',则无法满足该约束。)

注意。 在此算法中,行(及行组)和列(及列组)既约束又受其包含的单元格尺寸的约束。设置列的宽度可能间接影响行的高度,反之亦然。

17.5.3 表格高度算法

表格的高度由 'table' 或 'inline-table' 元素的 'height' 属性决定。取值为 'auto' 表示高度等于行高之和加上任何单元格间距或边框。其他取值被视为最小高度。CSS 2.1 并未定义当 'height' 属性导致表格高度超过正常高度时,多余空间应如何分配。

注意。 CSS 的未来更新可能会进一步规定此行为。

一旦用户代理拥有该行中所有单元格,可计算 'table-row' 元素的盒子高度:它是该行的计算后 'height'、行中每个单元格的计算后 'height',以及单元格所需的最小高度 (MIN) 三者的最大值。对 'table-row' 而言,'height' 为 'auto' 表示布局使用的行高为 MIN。MIN 取决于单元格盒子高度和单元格盒子对齐方式(类似于 行框 高度的计算)。CSS 2.1 并未定义当使用百分比值指定表格单元格和表格行的高度时,如何计算它们的高度。CSS 2.1 也未定义行组上 'height' 的含义。

在 CSS 2.1 中,单元格盒子的高度是内容所需的最小高度。表格单元格的 'height' 属性可以影响行的高度(见上文),但并不会增加单元格盒子的高度。

CSS 2.1 并未规定跨越多行的单元格如何影响行高的计算,只要求涉及的所有行的高度之和必须足以容纳跨越这些行的单元格。

'vertical-align' 属性决定每个表格单元格在行内的对齐方式。每个单元格的内容以及行本身都有基线、顶部、居中和底部。在表格的语境中,'vertical-align' 的取值具有如下含义:

baseline
单元格的基线与它跨越的第一行的基线保持同一高度(下面会给出单元格和行基线的定义)。
top
单元格框的顶部与它所跨越的第一行的顶部对齐。
bottom
单元格框的底部与它所跨越的最后一行底部对齐。
middle
单元格的中心与它所跨越行的中心对齐。
sub, super, text-top, text-bottom, <length>, <percentage>
这些取值不适用于单元格;单元格始终以基线对齐。

单元格的基线是单元格中第一个流入的 行框 的基线,或者是单元格中第一个流入的表格行的基线,两者取先出现的。如果既没有行框也没有表格行,则基线为单元格盒子内容边缘的底部。为了确定基线,带有滚动机制的流入盒子(参见 'overflow' 属性)必须视为已经滚动到其原始位置。请注意,单元格的基线可能会落在其底部边框以下,参见下面的 示例

在所有设置了 'vertical-align: baseline' 的单元格中,单元格盒子顶部到基线的最大距离用于确定该行的基线。下面是一个示例:

示例:垂直对齐单元格的示例   [D]

示意图展示了不同 'vertical-align' 取值对表格单元格的影响。

单元格 1 和 2 的盒子都以各自的基线对齐。单元格 2 在基线以上的高度最大,因此它决定了该行的基线。

如果某行没有任何单元格盒子对齐到基线,则该行的基线为该行中最低单元格的内容底部边缘。

为了避免歧义,单元格的对齐按以下顺序进行:

  1. 首先定位那些基线对齐的单元格,这一步会确定该行的基线。随后定位具有 'vertical-align: top' 的单元格。
  2. 此时行已经拥有顶部(可能还有基线),并且拥有一个临时高度——从顶部到目前为止定位的单元格中最低的底部的距离。(参见下文关于单元格内边距的约束。)
  3. 如果任何剩余的单元格(即在底部或中间对齐的单元格)的高度大于当前行高,则通过降低底部将行的高度增加到这些单元格的最大值。
  4. 最后定位其余单元格。

比行高还小的单元格盒子会在顶部或底部获得额外的内边距。

此示例中的单元格其基线位于底部边框下方

div { height: 0; overflow: hidden; }

<table>
 <tr>
  <td>
   <div> Test </div>
  </td>
 </tr>
</table>

17.5.4 列中的水平对齐

单元格盒子内部的行内级内容的水平对齐方式可以通过该单元格上的 'text-align' 属性值来指定。

17.5.5 行列的动态效果

'visibility' 属性对行、行组、列和列组元素可取值 'collapse'。该值会导致整行或整列从显示中移除,并且原本被该行或列占据的空间可以被其他内容使用。跨越被折叠行或列的单元格会被裁剪。折叠行或列本身并不会影响表格的其它布局。这使得可以在不重新布局表格的情况下动态地删除表格行或列,以适应列约束的潜在变化。

17.6 边框

CSS 为表格单元格的边框提供了两种截然不同的模型。一种最适合所谓的 分离边框,即每个单元格单独拥有边框;另一种适用于从表格一端延伸到另一端的连续边框。许多边框样式可以用任一模型实现,因此通常取决于个人喜好。

'border-collapse'
  collapse | separate | inherit
初始值  separate
应用于  ‘table’ 和 ‘inline-table’ 元素
可继承  
百分比  不适用
媒体  视觉
计算值  按指定值

此属性用于选择表格的边框模型。值 'separate' 选择分离边框模型,值 'collapse' 选择折叠边框模型。以下将分别介绍这两种模型。

17.6.1 分离边框模型

‘border-spacing’
  <length> <length>? | inherit
初始值  0
应用于  'table' 和 'inline-table' 元素*
可继承  
百分比  不适用
媒体  视觉
计算值  两个绝对长度

* 注意:用户代理也可能把 'border-spacing' 属性应用于 'frameset' 元素。哪些元素算作 'frameset' 并未在本规范中定义,由文档语言决定。例如,HTML4 定义了 <FRAMESET> 元素,XHTML 1.0 则定义了 <frameset> 元素。'frameset' 元素上的 'border-spacing' 属性可以作为非标准 'framespacing' 属性的有效替代。

长度值指定相邻单元格边框之间的间距。如果只指定一个长度,则同时作为水平和垂直间距;如果指定两个,则第一个为水平间距,第二个为垂直间距。长度不得为负值。

表格边框与位于表格边缘的单元格边框之间的距离等于该侧的表格内边距加上相应的边框间距。例如,在右侧,距离为 padding-right + horizontal border-spacing

表格的宽度是从左内部内边距边缘到右内部内边距边缘的距离(包括边框间距但不包括内边距和边框)。

然而,在 HTML 与 XHTML 1 中,

元素的宽度是从左边框边缘到右边框边缘的距离。

注意: 在 CSS3 中,这一特殊要求将通过 UA 样式表规则和 'box-sizing' 属性来定义。

在该模型中,每个单元格都有独立的边框。'border-spacing' 属性指定相邻单元格边框之间的距离。在这段空间内,行、列、行组和列组的背景是不可见的,从而让表格背景透显。行、列、行组和列组本身不能拥有边框(即用户代理必须 ignore 这些元素的边框属性)。

示例

下图中的表格可能是如下样式表的结果:

table      { border: outset 10pt; 
             border-collapse: separate;
             border-spacing: 15pt }
td         { border: inset 5pt }
td.special { border: inset 10pt }  /* The top-left cell */

带有 border-spacing 的表格   [D]

一个将 'border-spacing' 设置为长度值的表格。请注意,每个单元格都有自己的边框,表格本身也有单独的边框。

17.6.1.1 空单元格的边框和背景: 'empty-cells' 属性

‘empty-cells’
  show | hide | inherit
初始值  show
应用于  ‘table-cell’ 元素
可继承  
百分比  不适用
媒体  视觉
计算值  按指定值

在分离边框模型中,此属性控制对没有可见内容的单元格的边框和背景的呈现方式。空单元格以及 'visibility' 属性为 'hidden' 的单元格被视为没有可见内容。除非单元格包含以下任意内容,否则被视为空:

当属性取值为 'show' 时,空单元格(以及正常单元格)会绘制边框和背景。

取值为 'hide' 表示不为空单元格绘制任何边框或背景(参见 17.5.1 的第 6 点)。此外,如果一行中的所有单元格均为 'hide' 且没有可见内容,则该行的高度为零,且该行仅在一侧保留垂直边框间距。

示例

下面的规则会导致所有单元格都绘制边框和背景:

table { empty-cells: show }

17.6.2 折叠边框模型

在折叠边框模型中,可以为单元格、行、行组、列和列组的全部或部分指定边框。HTML 的 “rules” 属性的边框也可以通过这种方式指定。

边框居中于单元格之间的网格线。用户代理必须在离散单位(屏幕像素、打印点)数为奇数的情况下,采用一致的取整规则。

下图展示了表格宽度、边框宽度、内边距以及单元格宽度之间的相互作用。它们的关系由下式给出,该式对表格的每一行都成立:

row-width = (0.5 * border-width0) + padding-left1 + width1 + padding-right1 + border-width1 + padding-left2 +...+ padding-rightn + (0.5 * border-widthn)

其中 n 为该行的单元格数,padding-leftipadding-righti 分别表示第 i 个单元格的左(右)内边距,border-widthi 表示第 i 与第 i+1 个单元格之间的边框宽度。

UA 必须通过检查表格首行的首个和末尾单元格来计算表格的初始左、右边框宽度。表格的左边框宽度为首个单元格折叠后左边框的一半,右边框宽度为末尾单元格折叠后右边框的一半。如果后续行的折叠左、右边框更宽,则超出部分会溢入表格的外边距区域。

表格顶部边框宽度通过检查所有其顶部边框与表格顶部边框折叠的单元格来计算,取最大折叠顶部边框的一半。底部边框宽度同理,取最大折叠底部边框的一半。

任何溢入外边距的边框在判断表格是否溢出祖先元素时(参见 'overflow')都要被计入。

显示单元格和边框宽度以及单元格内边距的示意图   [D]

示意图显示了单元格、边框以及单元格内边距的宽度。

请注意,在此模型中,表格宽度包含了一半的表格边框。此外,该模型中表格本身没有内边距(但有外边距)。

CSS 2.1 未定义表格元素背景的边缘到底在何处。

17.6.2.1 边框冲突解决

在折叠边框模型中,每个单元格的每一边都可能由多个元素(单元格、行、行组、列、列组以及表格本身)通过边框属性共同指定,这些边框在宽度、样式和颜色上可能各不相同。原则是:在每个边缘,选择“最抢眼”的边框样式;若出现 'hidden' 样式,则该边框无条件关闭。

以下规则决定在冲突情况下哪种边框样式“获胜”:

  1. 具有 'border-style' 为 'hidden' 的边框优先于所有其他冲突边框。任何取值为 'hidden' 的边框都会抑制该位置的所有边框。
  2. 样式为“none”的边框优先级最低。只有当此边缘汇合的所有元素的边框属性均为“none”时,才会省略该边框(但请注意,“none”是边框样式的默认值)。
  3. 如果没有样式为 'hidden',且至少有一个样式不是 'none',则窄边框会被更宽的边框取代。如果多个边框拥有相同的 'border-width',则按以下顺序优先选择样式:'double'、'solid'、'dashed'、'dotted'、'ridge'、'outset'、'groove',最低级别为 'inset'。
  4. 如果冲突的边框仅在颜色上不同,则单元格上的样式胜过行上的样式,行上的胜过行组,行组的胜过列,列的胜过列组,最后是表格。当同类型的两个元素冲突时,位于左侧(若表格 'direction' 为 'ltr',则左;若为 'rtl' 则右)且更靠上的元素获胜。

示例

下面的示例说明了这些优先级规则的实际使用。该样式表:

table          { border-collapse: collapse;
                 border: 5px solid yellow; }
*#col1         { border: 3px solid black; }
td             { border: 1px solid red; padding: 1em; }
td.cell5       { border: 5px dashed blue; }
td.cell6       { border: 5px solid green; }

配合以下 HTML 源码:

<TABLE>
<COL id="col1"><COL id="col2"><COL id="col3">
<TR id="row1">
    <TD> 1
    <TD> 2
    <TD> 3
</TR>
<TR id="row2">
    <TD> 4 
    <TD class="cell5"> 5
    <TD class="cell6"> 6
</TR>
<TR id="row3">
    <TD> 7
    <TD> 8
    <TD> 9
</TR>
<TR id="row4">
    <TD> 10
    <TD> 11
    <TD> 12
</TR>
<TR id="row5">
    <TD> 13
    <TD> 14
    <TD> 15
</TR>
</TABLE>

将产生类似如下的效果:

带有折叠边框的表格示例   [D]

一个带有折叠边框的表格示例。

示例

下面是一个隐藏折叠边框的示例:

两条省略边框的表格   [D]

两条内部边框被省略的表格。

HTML 源码

<TABLE style="border-collapse: collapse; border: solid;">
<TR><TD style="border-right: hidden; border-bottom: hidden">foo</TD>
    <TD style="border: solid">bar</TD></TR>
<TR><TD style="border: none">foo</TD>
    <TD style="border: solid">bar</TD></TR>
</TABLE>

17.6.3 边框样式

以下 'border-style' 的部分取值在表格中的意义与在其他元素上不同,列表中已用星号标记。

none(无)
无边框。
*hidden
等同于 'none',但在 折叠边框模型 中同样会抑制任何其他边框(参见 边框冲突 部分)。
dotted
边框是一系列点。
dashed
边框是一系列短线段。
solid
边框是一条单线段。
double
双实线边框。两条线与它们之间的间距之和等于 'border-width' 的值。
groove
边框看起来像是刻在画布上。
ridge
'groove' 的反面:边框看起来像是从画布上凸出来的。
*inset
分离边框模型 中,边框让整个盒子看起来像嵌入在画布中;在 折叠边框模型 中,则绘制效果等同于 'ridge'。
*outset
分离边框模型 中,边框让整个盒子看起来像从画布中突起;在 折叠边框模型 中,则绘制效果等同于 'groove'。