17 表格

内容

17.1 表格简介

本章定义了CSS中表格的处理模型。布局是该处理模型的一部分。对于布局,本章介绍了两种算法。第一种是固定表格布局算法,是明确定义的,而第二种,自动表格布局算法,本规范并没有完整定义它

对于自动表格布局算法,有些应用广泛的实现已经达到了相当接近的可交互性(relatively close interoperability)

表格布局可以用来表示数据间的表关系。编写者在文档语言中指定这些关系,用CSS 2.1指定其表现

在可视化媒体中,CSS表格也可以用来实现特定的布局。这种情况下,编写者不应该在文档语言中使用表格相关的元素,而应该给相关结构元素应用CSS来实现需要的布局

编写者可以把表格当作一个矩形单元网格来指定其视觉格式 。单元格的行和列会被组织进行组(row group)和列组(column group)。在行,列,行组,列组和单元格的周围可以绘制边框(CSS 2.1中有两种边框模型)。编写者可以把单元格中的数据垂直或者水平对齐,以及对齐一行或一列里的所有单元格中的数据

示例:

用HTML 4描述的一个简单的3行,3列表格:

<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元素),3行(TR元素),3个表头单元格(TH元素)和6个数据单元格(TD元素)。注意,本例中的3列是隐式指定的:列数与表头和数据单元格需要的列数相同

下列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.1允许编写者通过'display'属性把文档语言元素“映射”到表格元素。例如,下列规则让FOO元素表现得像HTML TABLE元素一样,让BAR元素表现得像CAPTION元素一样:

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

我们在接下来的小节中讨论各种表格元素。本规范中,术语表格元素指的是表格创建中涉及的任意元素。内部表格元素是指生成行,行组,列,列组或者单元格的元素

17.2 CSS表格模型

CSS表格模型基于HTML4表格模型,其表格结构与表格的可视化布局极为相似。该模型中,一个表格由一个可选的标题和任意行数的单元格组成。表格模型可以说是“以行为主(row primary)”的,因为编写者在文档语言中显式指定行而不是列。列是在指定好所有行后衍生出来的--每行的第一个单元格属于第一列,第二个属于第二列,等等)。行和列可以被结构化分组,并且这种分组会反映在表现中(例如,可以在一组行周围绘制边框)

因此,表格模型由表格,标题,行,行组(包括表头组和footer组),列,列组和单元格组成

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',但对于可视化格式而言,该行组总是显示在所有其它行和行组之后,在所有底部标题之前。打印用户代理可能会在每一页重复跨越多页的footer行。如果一个表格含有多个具有'display: table-footer-group'的元素,只有第一个会被渲染成footer,其它的就当它们具有'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类型。例如,一个设置了'display: table-cell'的图片将填满可用的单元格空间,并且它的尺寸会像普通单元格一样被用于表格尺寸算法

'display'被设置为'table-column'或者'table-column-group'的元素不会被渲染(就像它们具有'display: none'一样),但它们有用,因为它们可以具有能为其代表的列引入样式的属性

附录中HTML 4的默认样式表描述了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 }

用户代理可能会忽略HTML表格元素上的这些'display'属性值,因为HTML表格可能为了向后兼容渲染,而用其它算法渲染。然而,这并不妨碍对HTML中其它非表格元素应用'display: table'

17.2.1 匿名表格对象

除HTML外的文档语言可能不包含CSS 2.1表格模型中的所有元素。这种情况下,“缺失的”元素必须要假定(assumed)出来,以配合表格模型。所有表格元素将在它周围自动生成必要的匿名表格对象,至少包括3个嵌套的对象,分别对应'table'/'inline-table'元素,'table-row'元素和'table-cell'元素。缺失的元素根据下列规则生成匿名对象(例如,可视化表格布局中的匿名盒):

在这些规则中,定义了下列术语:

行组盒(row group box)
'table-row-group','table-header-group'或者'table-footer-group'
适当的表格子级(proper table child)
'table-row'盒,行组盒,'table-column'盒,'table-column-group'盒或者'table-caption'盒
适当的表格行父级(proper table row parent)
'table'或者'inline-table'盒或者行组盒
内部表格盒(internal table box)
'table-cell'盒,'table-row'盒,行组盒,'table-column'盒或者'table-column-group'盒
表容器(tabular container)
'table-row'盒或者适当的表格行父级
连续的(consecutive)
如果两个兄弟盒没有除只含空白字符的匿名行内盒外的中间兄弟,它们就是连续的。如果一系列兄弟盒中每个盒都与(该序列中)它前面的那个是连续的,那么这些兄弟盒是连续的

这些规则中,流外(out-of-flow)元素被视为宽高都为0的行内元素,其包含块也根据这些规则来选择

下列步骤分3个阶段执行

  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. 生成缺失的子级容器(wrapper):
    1. 如果一个'table'或者'inline-table'盒的子级C不是一个适当的表格子级,就在CC的所有连续的非适当的表格子级兄弟周围生成一个匿名'table-row'盒
    2. 如果一个行组盒的子级C不是一个'table-row'盒,就在CC的所有连续的非'table-row'盒的兄弟周围生成一个匿名'table-row'盒
    3. 如果一个'table-row'盒的子级C不是一个'table-cell',就在CC的所有连续的非'table-cell'盒兄弟生成一个匿名'table-cell'盒
  3. 生成缺失的父级:
    1. 对于一系列连续的内部表格和'table-caption'兄弟中的每一个'table-cell'盒C,如果C的父级不是一个'table-row',就在CC的所有连续的'table-cell'盒兄弟周围生成一个匿名'table-row'盒
    2. 对于一系列连续的适当的表格子级中的每个适当的表格子级C,如果C缺少父级(misparented),就在CC的所有连续的适当的表格子级兄弟周围生成一个匿名'table'或者'inline-table'盒T(如果C的父级是一个'inline'盒,那么T必须是一个'inline-table'盒,否则就必须是一个'table'盒)
      • 如果一个'table-row'的父级既不是一个行组盒也不是一个'table'或者'inline-table'盒,它就缺少父级(misparented)
      • 如果一个'table-column'的父级既不是一个'table-column-group'盒也不是一个'table'或者'inline-table'盒,它就缺少父级(misparented)
      • 如果一个行组盒,'table-column-group'盒或者'table-caption'盒的父级既不是一个'table'盒也不是一个'inline-table'盒,它就缺少父级(misparented)

示例:

在这个XML示例中,假定'table'元素包含HBOX元素:

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

因为关联的样式表是:

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

示例:

本例中,假定3个'table-cell'元素包含行中的文本。注意文本被进一步包进了匿名行内盒中,如视觉格式化模型中所述:

<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'时,各种border属性才适用于列。这种情况下,在列和列组上设置的边框将输入到冲突处理算法中,以选择每个单元格边界的边框样式
'background'
只有在单元格和行背景透明时,才可以通过background属性设置列中单元格的背景。见“表格层与透明性”
'width'
'width'属性给定了最小列宽
'visibility'
如果一列的'visibility'被设置为'collapse',该列中的元素都不会被渲染,并且跨越到其它列的单元格会被裁剪。此外,表格宽度会减掉该列所占的宽度。见下面的“动态效果”。'visibility'的其它值不影响(列中元素)

示例:

下面是一些给列设置属性的样式规则示例。前两条规则共同实现了HTML 4值为"cols"的"rules"属性。第3条规则让"totals"列变为蓝色,最后2条规则展示了怎样通过固定布局算法让一列(具有)固定大小

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')元素

这两种情况下,表格都会生成一个叫做表格容器盒(table wrapper box) 的主块盒,它包含表格盒本身以及所有标题盒(按文档顺序)。表格盒是一个含有该表格内部表格盒的块级盒。标题盒是保留其原本的内容,内边距,外边距和边框区的块级盒,会被当作表格容器盒中的常规块盒来渲染。标题盒放在表格盒前面还是后面由'caption-side'属性决定,如下所述

如果表格是块级的,表格容器盒是一个'block'盒,而如果表格是行内级的,(表格容器盒)就是'inline-block'盒。表格容器盒建立了一个块格式化上下文。表格盒(非表格容器盒)用来对一个'inline-table'进行基线垂直对齐。表格容器盒的的宽度是它里面的表格盒的边框边界宽度(border-edge width),如17.5.2节所述。表格上'width'和'height'的百分比是相对于表格容器盒的包含块的,而不是表格容器盒本身

表格元素上'position','float','margin-*','top','right','bottom'和'left'属性的计算值被应用在表格容器盒上,而不是表格盒。所有其它不可继承的属性值应用在表格盒上,而不是表格容器盒(如果表元素的值未在表格和表格容器盒中使用,就用初始值代替)

A table with a caption above
it

上方有标题的表格图

17.4.1 标题定位与对齐

'caption-side'
Value:  top | bottom | inherit
Initial:  top
Applies to:  'table-caption'元素
Inherited:  yes
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

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

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对行和列跨度(row and column spans)施加了自己的限制

  1. 每个行框占据一行网格单元。行框一起按照源文档中出现的顺序从上到下铺满表格(即,表占用的网格行与行元素的数量完全相同)
  2. 一个行组与它所包含的行占据的网格单元相同
  3. 一个列盒占据一列或者多列网格单元。列盒按照其出现顺序一个挨一个地放置。第一列可能在左边或者右边,取决于表格'direction'属性的值
  4. 一个列组盒与它所包含的列占据的网格单元相同
  5. 单元格可以跨越多个行或者列(尽管CSS 2.1没有定义怎样确定跨越的行或者列的数量,但用户代理可能有关于源文档的特殊信息,CSS将来的更新可能会提供一种用CSS语法来表达这些信息的方式)。因此,每个单元格都是一个矩形框,宽高为一个或者多个网格单元。该矩形的顶行位于由单元格的父级指定的行中。该矩形必须尽量向左,但该单元格在第一列中占据的部分不能与任何其它单元格盒重叠(即,一个从之前行开始的跨行单元格),而且该单元格必须位于同一行中所有在源文档中更早出现的单元格的右边。如果这个位置会让一个跨列单元格与一个来自之前行的跨行单元格重叠的话,CSS没有定义结果:实现可以重叠单元格(正如许多HTML实现的做法)或者把后一个单元格移动到右边,以避免这种重叠(如果表格的'direction'属性是'ltr'的话,该约束成立。如果'direction'是'rtl',交换前两句话中的“左边”和“右边”)
  6. 一个单元格盒不能超出表格的最后一行或者行组,用户代理必须缩短它直到能适应

合并边框模型中,行,列,行组和列组的边缘与单元格边框所在的假想网格线一致(因此,该模型中,所有行恰好铺满表格,不会留下空白,列也是这样)。在独立边框模型中,边与单元格的border边完全一致(因此,该模型中,行,列,行组或者列组之间可能存在空白,对应'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>

用户代理可以自由视觉上重叠单元格,如左图。或者移动单元格来避免视觉重叠,如右图

One table with overlapping
cells and one without   [D]

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

17.5.1 表格层与透明性

为了找出每个表格单元背景,不同的表格元素可以被看作位于6个叠加的层上。其中某一层中设置在某个元素上的背景只有当它上方的层都具有透明背景时,才可见

schema of table layers   [D]

表格层级图解

  1. 最底层是个单一平面,表示表格盒本身。和所有盒一样,它可以是透明的
  2. 下一层包含列组。每个列组从顶行单元格的顶部延伸到底行单元格的底部,从它最左端的列的左边界到它最右端的列的右边界。背景恰好完全覆盖列组中所有的单元格区域,即使它们跨越到了列组外,但这种区域上的差异不会影响背景图片定位
  3. 列组上面是表示列盒的区域。每列的宽度与列组相同,高度和列中的常规(单列跨度)单元格相同。背景恰好完全覆盖列中所有单元格区域,即使它们跨越到了列外,但这种区域上的差异不会影响背景图片定位
  4. 下一层包含行组,每个行组从它第一列顶部单元格的左上角延伸到最后一列底部单元格的右下角
  5. 倒数第二层包含行。每行的宽度与行组相同,高度和行中的常规(单行跨度)单元格相同。与列类似,背景恰好完全覆盖行中所有的单元格区域,即使它们跨越到了行外,但这种区域上的差异不会影响背景图片定位
  6. 最顶层包含单元格自身。如图所示,虽然所有行都含有相同数目的单元格,但并非每个单元格都有具体内容。在独立边框模型'border-collapse'为'separate')中,如果它们的'empty-cells'属性值为'hide',这些“空”单元格的单元格,行,行组,列和列组的背景都将是透明的,会让表格背景显示出来

一个“缺失单元格(missing cell)”是一个没有被元素或伪元素占据的行/列网格中的单元格。缺失单元格会被当作一个占据该网格位置的匿名table-cell盒

下例中,第一行含有4个非空单元格,而第二行只含有一个非空单元格,因此,表格背景会透出来,除了第一行中那个跨越到了该行的单元格的所在的位置。下列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>

可能会被格式化成这样:

Table with three empty cells
  in bottom row   [D]

底行具有空元素的表格

注意,如果表格具有'border-collapse: separate',由'border-spacing'属性给定的区域的背景总是该表格元素的背景。见独立边框模型

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

CSS没有为表格定义一种“最佳”布局,因为在很多场景下,最佳的定义是个品味问题(a matter of taste)。CSS只定义了用户代理在布局表格时必须遵守的一些约束。用户代理可以用任何它们想用的算法来实现,并且可以自由选择偏重渲染速度还是精确程度,设定了“固定布局算法”时除外

注意,本节重写了10.3节描述的用于计算宽度的规则。特殊的,如果一个表格的外边距被设置为'0',宽度被设置为'auto',表格将不会自动改变大小填满其包含块。然而,一旦表格'width'的计算值确定了(用下面给出的算法,或者在适当的时候使用某些依赖UA的其它算法),就应用10.3节的其它部分。因此,例如,左右外边距为'auto'让表格居中

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

'table-layout'
Value:  auto | fixed | inherit
Initial:  auto
Applies to:  'table'和'inline-table'元素
Inherited:  no
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

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

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

下文描述了这两种算法

17.5.2.1 固定表格布局

用这种(快速)算法,表格的水平布局不依赖单元格的内容,它只取决于表格宽度,列宽和边框或者单元格间距

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

示例:

'width'为'auto'时,如果UA支持固定表格布局,下列(规则)将会创建一个比其包含块窄4em的表格:

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

在固定表格布局算法中,每列的宽度由下述规则决定:

  1. 'width'属性值不为'auto'的列元素所在的列宽度就设置为该宽度值
  2. 否则,由第一行中'width'属性值不为'auto'的单元格确定该列的宽度。如果单元格跨越了多列,就给宽度除以列数
  3. 所有剩余列均分剩余的水平表格空间(减去边框或单元格间距)

表格的宽度为表格元素的'width'值与列宽之和(加上单元格间距或者边框)两者之间的较大值。如果表格宽度比列宽之和还宽,额外的空间应该分布在各列中

如果一个后续行具有的列数目大于由table-column元素确定的数值与由第一行确定的数值两者之间的较大值,那么就不渲染额外的列。CSS 2.1没有定义渲染的列和表格的宽度,在使用'table-layout: fixed'时,编写者不应该省掉(omit)第一行中的列

按这种方式,一旦接收到了完整的第一行,用户代理就可以开始布局表格了。后续行中的单元格不影响列宽。所有内容溢出的单元格,用'overflow'属性来确定是否裁剪溢出的内容

17.5.2.2 自动表格布局

该算法中(一般要求最多遍历两趟(two passes)),表格的宽度由它所包含的列(和中间边框)的宽度决定。该算法反映了编写本规范时几种流行的HTML用户代理的行为。'table-layout'为'auto'时,不要求UA实现该算法来决定表格布局。它们可以用任何其它算法,即使会导致不同的行为

自动表格布局的输入必须只包括包含块的宽度、表格及其所有后代的内容及设置的CSS属性

注意 在CSS3中,这块可能会被定义得更详细

本节剩余部分是非规范的

该算法可能很低效,因为它需要用户代理在确定最终布局之前,拿到表格中所有内容,并且可能需要多趟遍历(more than one pass)

列宽由下列步骤决定:

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

    然后,计算每个单元格的“最大”宽度:格式化内容,不考虑除显式换行外的换行

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

  3. 对于每个跨越多列的单元格,增加其所跨列的最小宽度,让它们至少与单元格一样宽。对于最大宽度也这样处理。如果可能的话,把跨越的所有列再扩宽差不多相同的宽度

  4. 对于每个'width'不为'auto'的列组元素,增加其所跨列的最小宽度,让它们至少与列组的'width'一样宽

这样每一列都有了一个最大和最小宽度

标题最小宽度(CAPMIN)是通过计算每个标题的最小标题外宽(outer width),作为含有被格式化为"display: block"的标题的假想表格单元的MCW。最小标题外宽中的最大值是CAPMIN

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

  1. 如果'table'或者'inline-table'元素的'width'属性的计算值(W)不为'auto',宽度的应用值就是W,CAPMIN,以及所有列加上单元格间距和边框(MIN)所需要的最小宽度三者之间的最大值,如果宽度的应用值大于MIN,额外的宽度应该分布在各列中
  2. 如果'table'或者具有'width: auto'的'inline-table'元素,宽度的应用值为表格包含块的宽度,CAPMIN和MIN三者之间的最大值。然而,如果CAPMIN或者列加上单元格间距和边框(MAX)所需要的最大宽度都小于包含块宽度的话,就用max(MAX, CAPMIN)

百分比值的列宽是相对于表格宽度的。如果表格具有'width: auto',百分比表示对列宽的约束,UA应该尝试满足它(显然,这并不总是可能的:如果列宽是'110%'的话,该约束无法满足)

注意 该算法中,行(和行组)和列(和列组)都受其所含的单元格尺寸的约束。设置列的宽度可能会间接影响行的高度,反之亦然

17.5.3 表格高度算法

表格的高度由'table'或者'inline-table'的'height'属性给定。'auto'值表示高度为行高度之和加上所有单元格间距和边框。所有其它值都会被当作最小高度。当'height'属性导致表格比其它情况更高时,CSS 2.1没有定义额外空间如何分布

注意 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>
这些值不适用于单元格,单元格会相对基线对齐

一个单元格的基线是该单元格中第一个流内行框,或者该单元格中第一个流内table-row的基线,以先出现的为准。如果没有这样的行框或者table-row,基线就是该单元格盒的内容边界的底部。为了找出基线,具有滚动机制(见'overflow'属性)的流内盒必须被当作滚动到其初始位置了。注意,单元格的基线可能低于于其下边框,见下面的示例

单元格盒的顶部到所有具有'vertical-align: baseline'的单元格的基线之间的最远距离用于设置行的基线,下面是个示例:

Example of vertically
  aligning the cells   [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中有两种不同的模型可以用来设置表格单元的边框。一种最适合围绕着各个单元格的所谓的独立边框,另一种适合从表格一端到另一端的连续边框。通过这两种模型能实现许多边框样式,所以用哪一种通常是喜好问题(a matter of taste)

'border-collapse'
Value:  collapse | separate | inherit
Initial:  separate
Applies to:  'table'和'inline-table'元素
Inherited:  yes
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

该属性选择了表格的边框模型。'separate'值选择独立边框模型,'collapse'值选择合并边框模型。这两种模型如下所述

17.6.1 独立边框模型

'border-spacing'
Value:  <length> <length>? | inherit
Initial:  0
Applies to:  'table'和'inline-table'元素*
Inherited:  yes
Percentages:  N/A
Media:  visual
Computed value:  两个绝对长度

*) 注意:用户代理也可以给'frameset'元素应用'border-spacing'属性。哪些元素是'frameset'元素不由本规范定义,由文档语言来定。例如,HTML4定义了一个<FRAMESET>元素,而XHTML 1.0定义了一个<frameset>元素。因此,一个'frameset'元素上的'border-spacing'属性可以用作非标准的'framespacing'属性的合法替代品

该长度指定了相邻单元格边框之间的距离。如果指定了1个长度,就把它作为水平和垂直间隔。如果指定了2个,第一个是水平间隔,第二个是垂直间隔。长度不能为负

表格边框与表格边缘上的单元格边框之间的距离为表格在该边的内边距加上相关边框间隔距离。例如,在右手边,该距离为右内边距 + 水平水平边框间隔

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

然而,在HTML和XHTML1中,<table>元素的宽度是从左边框边界到右边框边界的距离

注意: 在CSS3中,这种特殊的需求将由UA样式表和'box-sizing'属性来定义

该模型中,每个单元格都有各自的边框。'border-spacing'属性指定了相邻单元格的边框之间的距离。这段间隔中,行,列,行组和列组的背景是不可见的,会让表格背景透出来。行,列,行组和列组没有边框(即,用户代理必须忽略这些元素的border属性)

示例:

下图中的表格可能是下面样式表产生的结果:

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

A table with
  border-spacing   [D]

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

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

'empty-cells'
Value:  show | hide | inherit
Initial:  show
Applies to:  'table-cell'元素
Inherited:  yes
Percentages:  N/A
Media:  visual
Computed value:  与指定值相同

在独立边框模型中,该属性控制不含可见内容的单元格周围的边框和背景的渲染。空单元格和'visibility'属性被设置为'hidden'的单元格被认为不含可见内容。单元格为空,除非它们包含下列一项或多项内容:

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

'hide'值表示不会在空单元格周围/后面渲染边框和背景(见17.5.1的第6点)。而且,如果行中的所有单元格都具有'hide'值,并且没有可见内容,那么该行为0高度,并且该行只有一边存在垂直边框间隔

示例:

如下规则会在所有单元格周围绘制边框和背景:

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的left (right) padding,border-widthi表示单元格ii + 1之间的边框

UA必须通过检查表格第一行中的第一个和最后一个单元格,为表格计算一个初始的左右边框宽度。表格的左边框宽度是第一个单元格的合并后左边框的一半,而表格的右边框宽度是最后一个单元格的合并后右边框的一半。如果后续行具有更大的合并后左右边框,那么所有超出的部分会涌进(spill into)表格的外边距区

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

在确定表格是否从某些祖先溢出(见'overflow')时,需要考虑所有涌进外边距的边框

Schema showing the widths of
  cells and borders and the padding of cells   [D]

此图展示了单元格的宽度和单元格的边框及padding

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

CSS 2.1没有定义表格元素的背景边界的位置

17.6.2.1 边框冲突处理

在合并边框模型中,每个元素的每条边上的边框可以通过各种与该边相关的元素(单元格,行,行组,列,列组和表格自身)上的border属性来指定,而且这些边框宽度,样式和颜色可能不同。经验法则是选择每边上最“醒目”的边框样式,除了所有'hidden'样式的出现会无条件切断(turn off)边框

下列规则决定发生冲突时哪种边框样式会“胜出”:

  1. 'border-style'为'hidden'的边框优先于所有其它冲突边框。具有该值的所有边框会抑制此位置的所有边框
  2. 具有'none'样式的边框优先级最低。只有在与该边相关的所有元素的border属性为'none'时,border才会被忽略(但注意,'none'是border style的默认值)
  3. 如果没有'hidden'样式,并且它们中至少有一个不为'none',那么窄边框会被丢弃,用更宽的那个。如果有好几个都具有相同的'border-width',那么样式按这样的顺序来选择:'double','solid','dashed','dotted','ridge','outset','groove'和优先级最低的:'inset'
  4. 如果border style只在颜色上有差异,那么设置在单元格上的样式优先于设置在行上的,(设置在行上的)优先于行组,列,列组和表格上的。当同类型的两个元素发生冲突时,更靠左(如果表格的'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>

将产生类似于这样的结果:

An example of a
  table with collapsed borders   [D]

具有合并边框的表格示例

示例:

一个隐藏合并边框的示例:

Table
  with two omitted borders   [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''border-width'的值
groove
边框看起来像是被刻进了画布
ridge
与'groove'相反:边框看起来像是要从画布里跑出来
*inset
独立边框模型中,边框让盒看起来像是被嵌进画布了。在合并边框模型中,绘制效果与'ridge'相同
*outset
独立边框模型中,边框让盒看起来像是要从画布里出来了。在合并边框模型中,绘制效果和'groove'相同