17 表格

内容

17.1 表格简介

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

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

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

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

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

示例:

这里有一个简单的三行三列表格,用 HTML 4 描述:

<TABLE>
<CAPTION>这是一个简单的3x3表格</CAPTION>
<TR id="row1">
   <TH>标题 1  <TD>单元格 1  <TD>单元格 2
<TR id="row2">
   <TH>标题 2  <TD>单元格 3  <TD>单元格 4
<TR id="row3">
   <TH>标题 3  <TD>单元格 5  <TD>单元格 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 }

然而,请注意行与行相交处的边框会重叠。row1 和 row2 之间的边框颜色(黑色或蓝色)和厚度(1px 或 3px)将是什么?我们将在边框冲突解决部分讨论这一点。

以下规则将表格标题放置在表格上方:

caption { caption-side: top }

前面的示例展示了 CSS 如何与 HTML 4 元素协同工作;在 HTML 4 中,各种表格元素(TABLE、CAPTION、THEAD、TBODY、TFOOT、COL、COLGROUP、TH 和 TD)的语义是明确定义的。在其他文档语言(如 XML 应用程序)中,可能没有预定义的表格元素。因此,CSS 2.2 允许作者通过 'display' 属性将文档语言元素“映射”到表格元素。例如,以下规则使 FOO 元素的行为像 HTML TABLE 元素,而 BAR 元素的行为像 CAPTION 元素:

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

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

17.2 CSS 表格模型

CSS 表格模型基于 HTML4 表格模型,其中表格的结构与表格的视觉布局紧密平行。在此模型中,表格由一个可选的标题和任意数量的单元格行组成。该表格模型被称为“行优先”,因为作者在文档语言中明确指定了行,而不是列。当所有行都被指定后,列才会被派生出来——每行的第一个单元格属于第一列,第二个属于第二列,等等。行和列可以在结构上进行分组,并且这种分组可以在呈现中得到反映(例如,可以在一组行周围绘制边框)。

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

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' 一样),但它们是有用的,因为它们可能具有某些属性,这些属性会为它们代表的列引发特定的样式。

HTML4 的默认样式表 中的附录展示了这些值在 HTML4 中的使用方式:

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 表格可能使用其他旨在向后兼容的渲染算法进行渲染。然而,这并不意味着不鼓励在 HTML 中的其他非表格元素上使用 'display: table'。

17.2.1 匿名表格对象

除 HTML 外的其他文档语言可能不包含 CSS 2.21 表格模型中的所有元素。在这些情况下,必须假设“缺失”的元素,以便表格模型能够正常工作。任何表格元素都会自动在自身周围生成必要的匿名表格对象,这些对象至少包含三个嵌套对象,分别对应 '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' 框。
表格式容器
一个 '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'。框 DA 的适当表格后代,如果 D 可以是 A 的后代而不导致生成任何中间的 'table' 或 'inline-table' 框。
    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,如果 C 的父元素不是 'table-row',则在 C 及其所有连续兄弟元素周围生成一个匿名 'table-row' 框,这些兄弟元素是 'table-cell' 框。
    2. 对于一系列连续的适当表格子元素中的每个适当表格子元素 C,如果 C 的父元素错误,则在 C 及其所有连续兄弟元素周围生成一个匿名 'table' 或 'inline-table' 框 T,这些兄弟元素也是适当的表格子元素。(如果 C 的父元素是一个 'inline' 框,则 T 必须是一个 'inline-table' 框;否则它必须是一个 'table' 框。)
      • 如果 'table-row' 的父元素既不是行组框,也不是 'table' 或 'inline-table' 框,则 'table-row' 的父元素错误。
      • 如果 'table-column' 框的父元素既不是 'table-column-group' 框,也不是 'table' 或 'inline-table' 框,则 'table-column' 框的父元素错误。
      • 如果行组框、'table-column-group' 框或 'table-caption' 框的父元素既不是 'table' 框,也不是 'inline-table' 框,则其父元素错误。

Example(s):

在此 XML 示例中,假设 'table' 元素包含 HBOX 元素:

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

因为关联的样式表是:

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

Example(s):

在此示例中,假设三个 'table-cell' 元素包含 ROWs 中的文本。请注意,文本进一步封装在匿名内联框中,如视觉格式模型中所述:

<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 中 "rules" 属性值为 "cols" 的效果。第三个规则将 "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' 属性决定,如下所述。

对于 'display: table',表格包装框是块级的;对于 'display: inline-table',则是内联级的。表格包装框建立一个块格式化上下文,而表格框建立一个表格格式化上下文。进行 'inline-table' 的基线垂直对齐时使用的是表格框(而不是表格包装框)。表格包装框的宽度是其中表格框的边框边宽度,如第 17.5.2 节所述。表格上的 'width' 和 'height' 的百分比是相对于表格包装框的包含块,而不是表格包装框本身。

表格元素上的 'position'、'float'、'margin-*'、'top'、'right'、'bottom' 和 'left' 属性的计算值用于表格包装框,而不是表格框;所有其他非继承属性的值用于表格框,而不是表格包装框。(如果表格元素的值未用于表格和表格包装框,则使用初始值。)

表格上方的标题图示

表格上方的标题图示。

17.4.1 标题的位置和对齐

名称: caption-side
值: top | bottom | inherit
初始值: top
适用于: 'table-caption' 元素
继承性:
百分比: N/A
媒体: 视觉
计算值: 按指定

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

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.2 没有定义跨越的行或列数量如何确定,但用户代理可能对源文档有特殊知识;未来的 CSS 更新可能会提供在 CSS 语法中表达这种知识的方法。)因此,每个单元格都是一个矩形框,宽度和高度分别为一个或多个网格单元格。这个矩形的顶行在其父元素指定的行中。矩形必须尽可能靠左,但其占据的第一个列中的部分不得与任何其他单元格框重叠(即,开始于前一行的跨行单元格),且单元格必须在与文档中更早出现的单元格相同行的右侧。如果这个位置会导致跨列的单元格与前一行的跨行单元格重叠,CSS 不定义结果:实现可以选择重叠单元格(如许多 HTML 实现中那样),也可以选择将后来的单元格向右移动以避免这种重叠。(如果表格的 'direction' 属性是 'ltr',则上述两句话中的“左”和“右”对换。)
  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',这些“空”单元格通过单元格、行、行组、列和列组背景是透明的,让表格背景透过。

“缺失单元格”是行/列网格中未被元素或伪元素占据的单元格。缺失的单元格将被渲染为如果一个匿名表格单元格框占据了它们在网格中的位置。

在以下示例中,第一行包含四个非空单元格,但第二行仅包含一个非空单元格,因此除了第一个单元格跨越此行之外,表格背景在此行中透出。以下 HTML 代码和样式规则

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<HTML>
  <HEAD>
    <TITLE>表格示例</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',则表格不会自动调整大小以填充其包含块。然而,一旦为表格找到的 'width' 的计算值(使用下面给出的算法或在适当情况下使用其他依赖于 UA 的算法),则第10.3节的其他部分仍然适用。因此,表格可以使用左右 'auto' 边距进行居中,例如。

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

名称: table-layout
值: auto | fixed | inherit
初始值: auto
适用于: 'table' 和 'inline-table' 元素
继承:
百分比: N/A
媒体: 视觉
计算值: 按指定

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

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

以下描述了这两种算法。

17.5.2.1 固定表格布局

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

表格的宽度可以通过 'width' 属性显式指定。对于 'display: table' 和 'display: inline-table','auto' 的值意味着使用自动表格布局算法。 但是,如果表格是正常流中的块级表格('display: table'),UA 可以(但不一定必须)使用 10.3.3 的算法来计算宽度并应用 固定表格布局,即使指定的宽度是 'auto'。

示例:

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

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

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

  1. 具有 'width' 属性值不是 'auto' 的列元素为该列设置宽度。
  2. 否则,第一行中的单元格具有 'width' 属性值不是 'auto' 的情况下,确定该列的宽度。如果单元格跨越多个列,则宽度按列划分。
  3. 剩余的列平均分配剩余的水平表格空间(减去边框或单元格间距)。

然后表格的宽度是表格元素的 'width' 属性的值与列宽之和(加上单元格间距或边框)中的较大者。如果表格比列宽,则应将多余的空间分配到各列上。

如果后续行的列数多于表格列元素确定的列数和第一行确定的列数中的较大者,则 可能不会呈现其他列。CSS 2.2 未定义 它们被渲染时列和表格的宽度。 使用 'table-layout: fixed' 时,作者不应省略第一行中的列。

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

17.5.2.2 自动表格布局

在此算法中(通常不需要超过两次通过),表格的宽度由其列的宽度(和之间的边框)决定。该算法反映了在本规范撰写时几种流行的 HTML 用户代理的行为。在 'table-layout' 为 'auto' 的情况下,UA 不需要实现此算法来确定表格布局;即使结果行为不同,它们也可以使用任何其他算法。

自动表格布局的输入只能包括包含块的宽度、表格及其任何后代的内容以及设置的任何 CSS 属性。

注意: 这可能会在 CSS3 中更详细地定义。

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

此算法可能效率低下,因为它要求用户代理在确定最终布局之前访问表格中的所有内容,并且可能需要多次通过。

列宽的确定如下:

  1. 计算每个单元格的最小内容宽度(MCW):格式化内容可能会跨越任意数量的行,但不能溢出单元格框。如果指定的 'width' (W) 大于 MCW,则 W 是最小单元格宽度。值为 'auto' 表示 MCW 是最小单元格宽度。

    还要计算每个单元格的“最大”单元格宽度:格式化内容时除了显式换行符出现的位置外不进行断行。

  2. 对于每列,从仅跨该列的单元格确定最大和最小列宽度。最小值是单元格最大最小宽度(或列的'width',以较大者为准)所需的宽度。最大值是单元格最大最大宽度(或列的'width',以较大者为准)所需的宽度。

  3. 对于跨越多列的每个单元格,增加所跨列的最小宽度,使其总宽度至少与单元格的宽度相同。对最大宽度也做相同处理。如果可能,尽量均匀地扩展所有跨列。

  4. 对于 'width' 值非 'auto' 的每个列组元素,增加其跨列的最小宽度,使其总宽度至少与列组的 'width' 值相同。

这会给出每列的最大和最小宽度。

标题宽度的最小值(CAPMIN)通过计算每个标题的最小标题外部宽度,即包含按“display: block”格式化的标题的假设表格单元的 MCW,来确定。最小标题外部宽度中的最大值为 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',则百分比表示列宽的限制,UA 应尝试满足该限制。(显然,这并不总是可能的:如果列宽为 '110%',则无法满足该限制。)

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

17.5.3 表格高度算法

表格的高度由 'table' 或 'inline-table' 元素的 'height' 属性决定。'auto' 值表示高度是行高的总和加上任何单元格间距或边框。任何其他值都被视为最小高度。CSS 2.2 未定义当 'height' 属性导致表格比预期高度更高时如何分配额外空间。

注意: 未来的 CSS 更新可能会对此进一步说明。

'table-row' 元素的框高度在用户代理获取该行中的所有单元格后计算:它是行的计算 'height'、该行中每个单元格的计算 'height',以及单元格所需的最小高度(MIN)中的最大值。'table-row' 的 'height' 值为 'auto' 时,布局时使用的行高为 MIN。MIN 取决于单元格框高度和单元格框对齐方式(类似于 行框高度的计算)。CSS 2.2 未定义使用百分比值指定表格单元格和行高时的高度计算方式。CSS 2.2 也未定义 'height' 在行组上的意义。

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

CSS 2.2 未指定跨越多行的单元格如何影响行高计算,但参与行高计算的行高总和必须足够大以容纳跨行单元格。

每个表格单元格的 '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> 测试 </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和XHTML1中,<table>元素的宽度是从左边框边缘到右边框边缘的距离。

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

在此模型中,每个单元格都有一个单独的边框。'border-spacing'属性指定相邻单元格边框之间的距离。在此空间中,行、列、行组和列组的背景是不可见的,允许表格背景透过显示。行、列、行组和列组不能有边框(即用户代理必须忽略这些元素的边框属性)。

示例:

下图中的表格可能是由这样的样式表生成的:

table      { border: outset 10pt; 
             border-collapse: separate;
             border-spacing: 15pt }
td         { border: inset 5pt }
td.special { border: inset 10pt }  /* 左上角的单元格 */

带有边框间距的表格   [D]

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

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

名称: empty-cells
值: show | hide | inherit
初始值: show
应用于: 'table-cell' 元素
是否继承:
百分比: 不适用
媒体: 视觉
计算值: 按指定

在分离边框模型中,此属性控制围绕没有可见内容的单元格的边框和背景的渲染。空单元格和属性'visibility'设置为'hidden'的单元格被认为没有可见内容。 单元格为空,除非它们包含以下一项或多项内容:

当此属性的值为'show'时,边框和背景会像正常单元格一样在空单元格周围/后面绘制。

值为'hide'表示不会在空单元格周围/后面绘制边框或背景(参见17.5.1中的第六点)。此外,如果一行中的所有单元格的值为'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之间的边框宽度。

用户代理必须通过检查表格第一行的第一个和最后一个单元格,计算表格的初始左右边框宽度。表格的左边框宽度是第一个单元格合并左边框的一半,右边框宽度是最后一个单元格合并右边框的一半。如果后续行的合并左右边框较大,则任何超出部分会溢出到表格的边距区域。

表格的顶部边框宽度通过检查所有与表格顶部边框合并的单元格来计算。表格的顶部边框宽度等于最大合并顶部边框的一半。底部边框宽度通过检查所有与表格底部边框合并的单元格来计算。底部边框宽度等于最大合并底部边框的一半。

任何溢出到边距的边框在确定表格是否溢出某些祖先元素时会被考虑(见'overflow')。

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

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

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

CSS 2.2 未定义表格元素的背景边缘在哪里。

17.6.2.1 边框冲突解决

在合并边框模型中,可以通过在各种元素(单元格、行、行组、列、列组和表格本身)上指定的边框属性来定义每个单元格每个边缘的边框,这些边框可能在宽度、样式和颜色上有所不同。通常的原则是,在每个边缘选择最“引人注目”的边框样式,但任何出现'style'为'hidden'的情况都会无条件地关闭边框。

以下规则决定了在冲突情况下,哪个边框样式“胜出”:

  1. 'border-style'为'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'相同。