CSS 表格模块 Level 3

W3C 工作草案

关于本文档的更多详细信息
此版本:
https://www.w3.org/TR/2025/WD-css-tables-3-20251216/
最新发布版本:
https://www.w3.org/TR/css-tables-3/
编辑者草案:
https://drafts.csswg.org/css-tables-3/
先前版本:
历史:
https://www.w3.org/standards/history/css-tables-3/
反馈:
CSSWG 问题仓库
规范内联
编辑者:
Keith CirkelMozilla
前编辑者:
François Remy受邀专家
Greg WhitworthMicrosoft
Bert BosW3C
L. David BaronGoogle
Markus MielkeMicrosoft
Saloni Mira RaiMicrosoft
为本规范建议编辑:
GitHub 编辑器
测试套件:
https://wpt.fyi/results/css/css-tables/
尚未准备好实现

本规范尚未准备好实现。 它存在于此仓库中,是为了记录想法并促进讨论。

在尝试实现本规范之前, 请通过 www-style@w3.org 联系 CSSWG。


摘要

本 CSS 模块定义了一个基于二维网格的布局系统,针对表格数据渲染进行了优化。在 表格布局模型中,每个显示节点都会被分配到一组连续行 与一组连续列之间的交叉区域,这些行和列本身由表格结构生成,并根据其 内容确定尺寸。

CSS 是一种用于描述结构化文档 (如 HTML 和 XML) 在屏幕、纸张等媒介上渲染方式的语言。

本文档状态

本节描述本文档在发布时的状态。 当前 W3C 出版物列表 以及本技术报告的最新修订版 可在 W3C 标准和草案索引中找到。

本文档由 CSS 工作组 使用推荐标准 轨道作为工作草案发布。 作为工作草案发布 并不意味着得到 W3C 及其会员的认可。

这是一份草案文档, 可能会在任何时候被其他文档更新、替换 或废弃。 除作为正在进行中的工作外,不应引用本文档。

请通过在 GitHub 中提交问题(首选) 发送反馈, 并在标题中包含规范代码 “css-tables”,如下所示: “[css-tables] …评论摘要…”。 所有问题和评论都会被归档。 或者,也可以将反馈发送至(已归档的)公开邮件列表 www-style@w3.org

本文档受 2025年8月18日 W3C 流程文档约束。

本文档由一个根据 W3C 专利政策 运作的工作组制作。 W3C 维护一个与该工作组交付物相关的任何专利 披露的公开列表; 该页面还包括披露专利的说明。 任何实际知晓某项专利且认为该专利 包含必要权利要求的个人, 必须按照 W3C 专利 政策第 6 节披露相关信息。

1. 引言

本节为非规范性内容

许多类型的信息(例如:过去一年收集的天气读数) 最适合以二维网格进行可视化表示, 其中行表示列表中的一个项目 (例如:某个日期,以及当天测量的各种天气属性), 而列表示某个项目属性的连续值 (例如:过去一年测量的温度)。

有时,为了让表示更容易理解, 网格中的某些单元格会用来表示其父行/列的描述或摘要, 而不是实际数据。 这种情况更常发生在 第一行和/或第一列中的单元格(称为表头) 或最后一行和/或最后一列中的单元格(称为表尾)。

这种表格数据表示通常称为表格。 表格布局可能被滥用于渲染其他类似网格的表示,如日历或时间线, 但当所表示的信息不适合作为数据表时, 作者应优先使用其他布局模式。

HTML 中表格的渲染长期以来已经在 HTML 规范中定义。 然而,它与 CSS 中定义的特性的交互长期以来仍未定义。 本规范的目标是定义 同时支持 HTML 表格和 CSS 的用户代理的预期行为。

请注意,本文档中定义的某些行为 并不是解决其目标问题的最合乎逻辑或最有用的方式, 但这些行为通常是兼容性要求的结果,而不是本规范 编辑者的有意选择。 希望使用更复杂布局的作者 鼓励依赖更现代的 CSS 模块,例如 CSS Grid。

测试

以下测试是崩溃测试, 它们与本规范所描述特性的常规用法有关, 但不绑定到任何特定的规范性陈述。


与表格布局大体相关的测试


1.1. 值定义

本规范遵循 CSS 属性 定义约定,该约定来自 [CSS2],并使用来自 值定义语法[CSS-VALUES-3]。 本规范中未定义的值类型定义于 CSS Values & Units [CSS-VALUES-3]。 与其他 CSS 模块结合使用可能会扩展这些值类型的定义。

除各属性定义中列出的属性特有值外, 本规范中定义的所有属性 还都接受 CSS-wide 关键字作为其属性值。 为了可读性,这里没有显式重复列出它们。

2. 内容模型

2.1. 表格结构

CSS 表格模型基于 HTML4 表格模型, 在该模型中,表格的结构与表格的视觉布局紧密对应。 在此模型中,表格由一个可选标题和任意数量的单元格行组成。

此外,相邻的行和列可以按结构分组,并且 这种分组可以体现在呈现中(例如,可以围绕一组行绘制边框)。

表格模型被称为“行优先”,因为 作者在文档语言中显式指定的是行,而不是列。 列会在所有行都指定后派生出来: 第一行的第一个单元格属于第一列 以及跨越所需的任意其他列(必要时会创建它们), 而该行后续的每个单元格都属于下一个可用列 以及跨越所需的任意其他列(必要时创建这些列); 后续行中的每个单元格都属于该行的下一个可用列(考虑 rowspan) 以及跨越所需的任意其他列(必要时创建这些列)。(见 § 3.3 确定行/列网格尺寸

总之,表格模型的一个实例由以下内容组成:

[见下方说明]
表格结构的两种表示方式(树与布局)

CSS 模型并不要求文档语言包含与这些组件一一对应的元素。 对于没有预定义表格元素的文档语言(如 XML 应用), 作者必须将文档语言元素映射为表格元素。 这是通过 display 属性完成的。

以下 display 值会将表格格式化规则分配给任意元素:

table(等同于 HTML: <table>)
指定某个元素定义一个表格, 当置于流布局中时,该表格是块级的。
inline-table (等同于 HTML:<table>)
指定某个元素定义一个表格, 当置于流布局中时,该表格是行级的。
table-row(等同于 HTML:<tr>)
指定某个元素是一行单元格。
table-row-group (等同于 HTML:<tbody>)
指定某个元素对若干行进行分组。

除非另有明确说明,本规范中提到的 table-row-groups 也包括专门的 table-header-groupstable-footer-groups

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-rowtable-row-group table-header-grouptable-footer-grouptable-columntable-column-grouptable-celltable-caption,则按 CSS Display 3 § 2.4 布局内部显示类型:table-* 和 ruby-* 关键字,会被视为行级 盒替换元素如果其 display 值为 tableinline-table,则按其外部显示类型表现, 如 CSS Display 3 § 2.1 流布局的外部 显示角色:block、inline 和 run-in 关键字所述。这是相对于 CSS 2.1 的破坏性 变更,但与实现相匹配。

测试

2.1.1. 术语

除了表格结构的显示类型外, 本规范还使用以下表述:

table wrapper box
一个围绕 table grid 盒生成的块容器盒,用于计入其拥有的每个table-caption 占据的任何空间。
table grid box
一个包含表格内部盒的块级盒,不包括其标题。
table-root 元素
一个内部显示类型table 的元素。
table-non-root 盒或元素
一个proper table child,或一个 table-cell 盒。
table-track 盒或 元素
一个 table-row,或 table-column 盒。
table-track-group 盒或元素
一个 table-row-group,或 table-column-group 盒。
proper table child 盒或元素
一个 table-track-grouptable-track,或 table-caption 盒。
proper table-row parent 盒或元素
一个 table-root 或一个 table-row-group 盒。
table-internal 盒或元素
一个 table-celltable-tracktable-track-group 盒。
tabular container
一个 table-rowproper table-row parent 盒。
连续
两个同级盒如果它们之间没有其他同级盒, 除了可选的、仅包含空白的匿名行内盒之外, 则它们是连续的。 一组同级盒如果序列中的每个盒都与其前一个盒连续, 则该序列是连续的。
测试
table grid
一个矩阵, 其中包含描述 table-root 的所有 table-rowstable-cells 位置所需的 尽可能多的, 这些位置由网格定维算法确定。

网格中的每一行可以对应一个 table-row,每一列可以对应一个 table-column

slot of the table grid
(r,c)table grid 中行 r 与列 c 相交所创建的可用 空间。

table grid 中的每个槽至少被一个 table-cell 覆盖(其中一些 是匿名的),最多被两个覆盖。 table-root 的每个 table-cell 至少覆盖一个槽。

覆盖多个槽的 table-cells 会密集地覆盖这些槽, 这意味着它们所覆盖的槽集合总能描述为一组四个严格正整数 (rowStart, colStart, rowSpan, colSpan),使得槽 (r,c) 被该 table-cell 覆盖 当且仅当 r 位于从 rowStart(包含)到 rowStart+rowSpan(不包含)之间的区间内, 且 c 位于从 colStart(包含)到 colStart+colSpan(不包含)之间的区间内;

这样的 table-cell 被称为从行 rowStart 和列 colStart 起始。 另外:

  • 如果某个 table-cell 起始于对应的行(相应地,列),则称它起始于某个 table-row (相应地,table-column)
  • 如果某个 table-row-group (相应地,table-column-group)包含该单元格的起始行 (相应地,列),则称该 table-cell 起始于该 table-row-group (相应地,table-column-group)

这样的 table-cell 被称为跨越所有符合上述条件的行 r 和列 c。 另外:

  • 如果某个 table-cell 跨越其对应的行(相应地,列),则称它跨越某个 table-row (相应地,table-column)
  • 对应于某一行(相应地,列)的 table-row (相应地,table-column)被称为 跨越该行(相应地,列)
  • table-row (相应地,table-column)被称为跨越网格的所有列(相应地, 行)
  • 包含某一行(相应地,列)的 table-row-group (相应地,table-column)被称为 跨越该行(相应地,列)
  • table-row-group (相应地,table-column)被称为跨越网格的所有列(相应地, 行)

2.2. 修正

HTML 以外的文档语言可能不包含 CSS 2.1 表格模型中的所有元素。 在这些情况下,为了让表格模型正常工作,必须假定存在这些“缺失”的元素。

任何 table-internal 元素在必要时都会自动围绕自身生成必要的 匿名表格对象。 table-root 的任何非 table-internal 后代在表格中必须具有一组祖先, 至少包含三个嵌套对象,分别对应于 table/inline-tabletable-row,以及 table-cell。 缺失的盒会导致按以下规则生成匿名盒

2.2.1. 修正算法

就这些规则而言,脱离流 元素表示为宽度和高度均为零的行内元素。 其包含块也会据此选择。

以下步骤分三个阶段执行:

  1. 移除无关盒:
    以下盒会像 display:none 一样被丢弃:
    1. table-column 的子项。
    2. table-column-group 的子项中不是 table-column 的子项。
    3. 仅包含空白且位于两个直接同级之间的匿名行内盒,其中每个直接同级都是 table-non-root 盒。
    4. 满足以下所有条件的匿名行内盒:
  2. 生成缺失的子包装器:
    1. 必须围绕 table-root 盒的每一组连续子项生成匿名 table-row 盒, 这些子项不是proper table child 盒。!!测试用例
    2. 必须围绕 table-row-group 盒的每一组连续子项生成匿名 table-row 盒, 这些子项不是 table-row 盒。!测试用例
    3. 必须围绕 table-row 盒的每一组连续子项生成匿名 table-cell 盒, 这些子项不是 table-cell 盒。!测试用例
  3. 生成缺失的父级:
    1. 必须围绕每一组连续 table-cell 盒 生成匿名 table-row 盒, 这些盒的父级不是 table-row测试用例
    2. 必须围绕每一组连续且父级错误的proper table child 盒 生成匿名 tableinline-table 盒。 如果该盒的父级是 inline、run-in 或 ruby 盒(或任何会对其子项执行 inlinification 的盒), 则必须生成 inline-table 盒; 否则必须生成 table 盒。 测试用例 测试用例 !测试用例
    3. 必须围绕每个 table-root 生成匿名 table-wrapper 盒。 对于 inline-table 盒,其显示类型为 inline-block; 对于 table 盒,其显示类型为 block。 table wrapper 盒会建立块格式化上下文。 当对 inline-table 进行基线垂直对齐时, 使用的是 table-root 盒(而不是 table-wrapper 盒)。 table-wrapper 盒的宽度是其内部 table grid 盒的 border-edge 宽度。 那些会依赖 table-wrapper 盒尺寸上的 widthheight 的百分比,改为相对于 table-wrapper 盒的包含块,而不是 table-wrapper 盒自身。
请注意,某些布局模式(如 flexbox 和 grid)会覆盖其子项的显示类型。 这些转换发生在表格修正之前。
请注意,floatposition 属性有时会影响 display 的计算值。 当这些属性用于本应是表格内部盒的内容时,它们会改为 block。 此转换发生在表格修正之前。
我们修改了本节来自 CSS 2.2 的文本,以便更容易阅读。 如果你发现这些更改导致的任何错误,请提交问题
测试

2.2.2. 修正盒的特征

除了其显示类型之外,为修正目的创建的匿名盒 不会接收任何特定样式或默认样式, 除非本规范另有说明。

这特别意味着 它们的计算背景为“transparent”, 它们的计算内边距为“0px”, 它们的计算 border-style 为“none”。

还值得提醒的是,匿名盒 会通过盒树继承属性值。

2.2.3. 示例

<div class="row">
  <div class="cell">George</div>
  <div class="cell">4287</div>
  <div class="cell">1998</div>
</div>

以下是关联的样式:

.row { display: table-row }
.cell { display: table-cell }

修正后,这会生成布局盒,就好像初始 HTML 如下:

<table>
  <tr>
    <td>George</td>
    <td>4287</td>
    <td>1998</td>
  </tr>
</table>

在此示例中,假定三个 table-cell 匿名盒包含各行中的文本。具有 display: table-row 的 div 内的文本会被封装到匿名行内盒中, 如视觉 格式化模型中所述:

<div class="inline-table">
  <div class="row">这是顶部行。</div>
  <div class="row">这是中间行。</div>
  <div class="row">这是底部行。</div>
</div>
.inline-table { display: inline-table; }
.row { display: table-row; }

这会生成布局盒,就好像初始 HTML 如下:

<table>
  <tr>
    <td>这是顶部行。</td>
  </tr>
  <tr>
    <td>这是中间行。</td>
  </tr>
  <tr>
    <td>这是底部行。</td>
  </tr>
</table>

3. 布局

3.1. 核心布局原则

不同于其他块级盒,表格默认不会填满其包含块。 当它们的 width 计算为 auto 时,它们的行为就好像指定了 fit-content 一样。 这不同于大多数块级盒,后者的行为就好像指定了 stretch 一样。

表格的 min-content width 是 适应其所有列的 min-content 宽度以及其不可分配空间所需的宽度。

表格的 max-content width 是 适应其所有列的 max-content 宽度以及其不可分配空间所需的宽度。

如果分配给表格的宽度大于其 min-content width可用宽度分配算法 将相应地调整列宽。

本节覆盖其他规范中描述的适用于计算宽度的一般用途规则。 特别是,如果表格的外边距设为 0 且宽度设为 auto, 该表格不会自动调整大小以填满其包含块。 然而,一旦找到表格 width 的使用值(使用下方给出的算法), 这些规则的其他部分仍然适用。 因此,例如可以使用左右 auto 外边距使表格居中。

3.2. 表格布局算法

要布局一个表格,用户代理必须应用以下操作:

  1. 确定表格所需的行/列数量。
    这是通过执行 § 3.3 确定行/列网格尺寸 中描述的步骤完成的。
  2. [A] 如果行/列网格至少有一个
    1. 确保每个单元格至少被一个单元格占据。
      这是通过执行 § 3.4 缺失单元格修正 中描述的步骤完成的。
    2. 计算每列的最小宽度。
      这是通过执行 § 3.8 计算表格度量 中描述的步骤完成的。
    3. 计算表格的宽度。
      这是通过执行 § 3.9.1 计算表格宽度 中描述的步骤完成的。
    4. 在各列之间分配表格的宽度。
      这是通过执行 § 3.9.3 分配算法 中描述的步骤完成的。
    5. 计算表格的高度。
      这是通过执行 § 3.10.1 计算表格高度 中描述的步骤完成的。
    6. 在各行之间分配表格的高度。
      这是通过执行 § 3.10.5 分配算法 中描述的步骤完成的。

    [B] 否则,布局一个空 表格

    1. 计算表格的宽度。
      这是通过返回 CAPMIN 与表格网格盒计算宽度 (包括边框和内边距)中的较大值完成的, 如果后者是确定的;否则使用零。
    2. 计算表格的高度。
      这是通过返回所有 table-caption 高度之和 (其宽度被设为表格宽度, 并适当考虑外边距) 与表格网格盒的计算高度(包括边框和内边距)之和完成的, 如果后者是确定的;否则使用零。
  3. 为每个 table-caption 和 table-cell 分配其位置和尺寸。
    这是通过运行 § 3.11 单元格、标题和其他内部 表格盒的定位中的步骤完成的。

下列示意图以另一种方式描述该算法, 以便更容易理解。

[见下方说明]
表格布局算法概览。非规范性。
测试

3.3. 确定行/列网格尺寸

表格结构一节所述, 表格具有多少行和列 可以从表格结构确定。 确定行/列网格尺寸,以及在该网格中为 table-cells 分配其 slot 都需要运行用于表格的 HTML 算法。

3.3.1. HTML 算法

不源自与其 display 类型等效的 HTML 表格元素的 CSS 盒, 需要先转换为其 HTML 等效物,然后才能应用该算法,见下文。 在本规范的这个级别中,无法仅用 CSS 指定单元格的跨越, 要做到这一点,需要使用 HTML td 元素。

应用 HTML5 表格格式化 算法, 其中盒表现得像与其 display 类型等效的 HTML 元素, 并且当且仅当其来源元素是相同类型的 HTML 元素时,使用其来源元素的属性 (否则,它们表现得就像没有任何属性一样)。

<ul class="table">
  <li><b></b><i>1</i></li>
  <li><b></b><i>2</i></li>
  <li><b></b><i>3</i></li>
</ul>
<style>
  ul.table { display: table; }
  ul.table > li { display: table-row; }
  ul.table > li > * { display: table-cell; }
</style>

产生的行/列网格与以下内容相同

<table><tbody>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
  <tr>
    <td></td>
    <td></td>
  </tr>
</tbody></table>
<!-- 使用 dom api 构建,因为这会被 html 解析器修正 -->
<grid style="display: table">
  <row style="display: table-row">
    <th rowspan="2">1</th>
    <colgroup style="display: table-cell" span="2" colspan="2">2</colgroup>
  </row>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</grid>

产生的行/列网格与以下内容相同

<table>
  <tr>
    <th rowspan="2">1</th>
    <td>2</td>
  </tr>
  <tr>
    <td>A</td>
    <td>B</td>
    <td>C</td>
  </tr>
</table>

请注意,第一行的第二个单元格没有应用 ```colspan=2```,因为其来源 元素不是 HTML TD 元素。

测试用例!!测试用例!测试用例!!测试用例!!测试用例

测试

3.3.2. 轨道合并

HTML 表格格式化算法有时会生成比正确布局表格所需更多的轨道。 这些轨道历来被用户代理忽略, 因此下一步会将它们完全移除,以避免在规范后续部分将它们作为例外处理。 我们试图通过这一更改保持功能不变,但如果你偶然发现 此更改导致的任何问题,请提交问题。

通过如下方式合并连续轨道,迭代地修改获得的网格: 只要获得的行/列网格中存在一个合格轨道,使得 没有 table-column/table-row 盒显式定义该轨道,并且 该轨道和前一个轨道被完全相同的一组单元格跨越, 则为了计算表格布局,必须将这两个轨道合并为一个单一轨道。 将跨越被删除轨道的单元格的跨越减一以进行补偿, 并在需要时类似地移动单元格起始所在的轨道。(见 spanning-ghost-rows 测试用例

对于自动模式下的表格, 就轨道合并算法而言,每个轨道都是一个合格 轨道。 对于固定模式下的表格, 只有行有资格以这种方式合并;这意味着每一列都会被保留。

最后,为 table-root 网格分配其正确的行数和列数(来自其 映射元素), 并为每个 table-cell 分配其准确的 rowStart/colStart/rowSpan/colSpan(来自其映射元素)。

测试

3.4. 缺失单元格修正

下节澄清并扩展 CSS 2.1 的陈述,即 缺失单元格会被渲染得好像一个匿名 table-cell 盒占据了它们在网格中的位置 (“缺失单元格”是行/列网格中尚未被任何 table-cell 盒覆盖的槽)。

一旦表格中的列数已知,任何 table-row 盒都必须被修改,使其 拥有足够的单元格来填满表格的所有列,同时考虑跨越。 新的 table-cell 匿名盒必须追加到其行内容中,直到满足此 条件。

测试

3.5. 表格布局模式

本节涵盖会修改表格布局方式的标志。 表格布局有三个主要标志:table-layoutborder-collapsecaption-sideborder-collapse 标志有一个可选的 border-spacing 参数。

3.5.1. table-layout 属性

名称: table-layout
值: auto | fixed
初始值: auto
适用于: table grid 盒
继承:
百分比: 不适用
计算值: 指定的关键字
规范顺序: 按语法
动画类型: 离散
测试

每当 table-layout 属性的计算值等于 fixed, 且表格根的指定宽度为 <length-percentage>min-contentfit-content 时, table-root 就被称为以固定模式布局。 当指定宽度不是这些值之一, 或者 table-layout 属性的计算值为 auto 时, table-root 就被称为以自动模式布局。

当 table-root 以固定 模式布局时, 在宽度计算中会忽略其 table-cells 的内容, 列尺寸的聚合算法只考虑属于第一行轨道的 table-cells, 因此布局只取决于为表格的 table-columns 或第一行单元格显式指定的值; 具有不确定宽度的列会在考虑具有确定宽度的列之后, 获得剩余空间的公平份额;如果没有剩余空间则为 0px (见 § 3.8.3 计算列度量)。

3.5.2. border-collapse 属性

名称: border-collapse
值: separate | collapse
初始值: separate
适用于: table grid 盒
继承:
百分比: 不适用
计算值: 指定的关键字
规范顺序: 按语法
动画类型: 离散

border-collapse 属性的值为 collapse 时, 相邻单元格的边框会合并在一起,使每个单元格只绘制共享边框的一半。 因此,其他一些属性(如 border-spacing)在此情况下不会应用 (见 § 3.6.2 适用于边框合并 模式的覆盖), (见 § 3.7 边框合并)。

在这种情况下,table-root 被称为以边框合并 模式布局。 否则,table-root 被称为以边框分离 模式布局。

测试
3.5.2.1. border-spacing 属性
名称: border-spacing
值: <length>{1,2}
初始值: 0px 0px
适用于: table grid 盒, 当 border-collapseseparate
继承:
百分比: 不适用
计算值: 两个绝对长度
规范顺序: 按语法
动画类型: 按计算值

这些长度指定边框分离模式中 相邻单元格边框之间的距离, 且不得严格为负。

如果指定一个长度,它同时给出水平和垂直间距。 如果指定两个长度,第一个给出水平间距,第二个给出垂直间距。

有关这如何影响表格布局的详细信息,见 § 3.8.1 计算不可分配空间

测试

3.5.3. caption-side 属性

名称: caption-side
值: top | bottom
初始值: top
适用于: table-caption
继承:
百分比: 不适用
计算值: 指定的关键字
规范顺序: 按语法
动画类型: 离散
测试

此属性指定 caption 盒相对于 table grid 盒的位置。 各值含义如下:

top
将 caption 盒定位在 table grid 盒上方。
bottom
将 caption 盒定位在 table grid 盒下方。
CSS2 描述了不同的宽度和水平对齐行为。 该行为本应在 CSS3 中 使用 top-outsidebottom-outside 值引入。#REF
Gecko 还支持 "left" 和 "right" 值,但目前本规范 并不试图定义它们对这些值的实现。
Gecko 在处理多个标题时存在一个缺陷。!测试用例

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

在此示例中,caption-side 属性将标题放置在表格下方。 标题将与表格的父级一样宽,并且标题文本将左对齐。

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

3.6. 样式覆盖

某些 css 属性在 css 表格内部的行为有所不同。 以下各节列出这些例外及其效果。

3.6.1. 适用于所有模式的覆盖

以下规则适用于所有表格,无论使用哪种布局模式。

3.6.2. 适用于边框合并模式的覆盖

当表格以边框合并模式布局时,适用以下规则:

3.7. 边框合并

整个本节是一项提案,旨在使合并边框的渲染更加合理。 由于实现差异非常明显,预计它会比其他一些部分需要更多讨论。 由于浏览器处理这一点的方式差异很大,如果不重新实现,就无法实现收敛。 本提案的一个主要关注点是支持尽可能多的情况,同时 将新表格实现所需的工作量保持得尽可能低。

背景: CSS+HTML 允许表格交汇处的边框模式出现前所未有的组合, 这使得正确支持所有情况变得困难; 事实上,某些组合并不是适定 问题, 因此没有任何渲染算法能够达到最优。

由于它们从简单事物(HTML)发展到非常复杂的事物(HTML+CSS), Web 浏览器当前使用的表格渲染模型(背景和边框)是不合理的 (意思是它们有缺陷、不可互操作,且完全不 CSS 化)。 许多通常的 CSS 假设被破坏,渲染结果存在巨大差异。

本提案旨在修复这一状况。

测试

border-collapsing 相对于 2.1 的破坏性变更 [Issue #604]

3.7.1. 合并边框的冲突解决

测试

当它们以边框合并模式布局时,共享边框的 table-roottable-cell 盒会尝试统一 它们的边框, 使其使用相同的样式、宽度和颜色进行渲染(只要可能)。 这是通过运行以下算法完成的。

3.7.1.1. 合并 边框的冲突解决算法
就本算法而言,“协调”一组边框是指 对给定的边框集合应用“合并 边框的协调算法”,并 将这些边框的使用值设置为该算法得出的值, 但具有不同于 none 的 border-image-source 的单元格除外: 它们保留其初始值。

对于 table-root 的任何 table-cell C°:

然后,对于该 table-root

当然,实现可以选择跳过前一个 算法的某些步骤, 只要它们能够证明这些步骤不会对最终结果产生可见影响; 某些边框会使用前述步骤被协调多次, 但阻止这一点会使规范更难阅读。
为了帮助读者 更好地理解该算法的作用, 这里概述了在示例表格上应用前述算法的主要步骤:

https://jsfiddle.net/bn3d1sm4/
https://jsfiddle.net/bn3d1sm4/1/
https://jsfiddle.net/bn3d1sm4/2/

https://jsfiddle.net/bn3d1sm4/15/
测试
3.7.1.2. 合并 边框的协调算法
就本算法而言,“考虑”某个边框的属性意味着: “如果其属性比 CurrentlyWinningBorderProperties 更具体, 则将 CurrentlyWinningBorderProperties 设置为其属性”。

更改合并边框协调中的 优先级?[Issue #606]

给定一个边框样式的有序集合(BC1, BC2, … 位于单元格 C1, C2, … 中), 执行以下算法,以确定这些冲突边框的边框属性使用值。

3.7.1.3. 边框样式的优先级

给定两个边框样式,具有最高优先级的边框样式是符合以下条件的边框样式……

  1. ……如果只有一个边框样式的 border-style 值为 "hidden",则为该边框样式
  2. ……一旦转换为 css 像素后,具有最大的 border-width
  3. ……具有在以下列表中最先出现的 border-style
    double, solid, dashed, dotted, ridge, outset, groove, inset, none

如果这些条件都不匹配,则两个边框具有相同的优先级。

3.8. 计算表格度量

测试

3.8.1. 计算不可分配空间

表格的不可分配 空间是 连续 table-cells 的边框之间距离 (以及 table-root 的边框与 table-cells 之间距离)的总和。

两个连续 table-cells 的边框之间的距离是 border-spacing,如果存在的话。

表格边框与 表格边缘单元格的边框之间的距离 是 表格在该侧的内边距, 加上相关的边框间距距离(如果有)。

例如,在 右侧,该距离为 padding-right + 水平 border-spacing。

3.8.2. 计算单元格度量

以下术语是表格或表格单元格的参数。 这些参数封装了具有不同 border-collapse 值(separate 或 collapse)的表格之间的差异, 从而使本节余下的小节不需要以不同方式引用它们。

cell intrinsic offsets
cell intrinsic offsets 是用于捕获表格单元格中与固有宽度计算相关的内边距和边框部分的术语。 它是一组用于 border-left-width、padding-left、padding-right 和 border-right-width 的计算值 (以及 margin-left 和 margin-right 的零值), 定义如下:
table intrinsic offsets
table intrinsic offsets 捕获表格中与固有宽度计算相关的内边距和边框部分。 它是一组用于 border-left-width、padding-left、padding-right 和 border-right-width 的计算值 (以及 margin-left 和 margin-right 的零值), 定义如下:

外边距不包含在 table intrinsic offsets 中,因为外边距的处理取决于 caption-side 属性。

在边框合并模式中 intrinsic offsets 的处理 [Issue #608]

总 水平边框间距
总水平边框间距为每个表格定义如下:
  • 对于以边框分离模式布局且至少包含 一列的表格, border-spacing 属性计算值的水平分量乘以表格中的列数加一
  • 否则为 0
offsets-adjusted min-width、width 和 max-width

测试用例。 测试用例。 测试用例。

outer min-contentouter max-content 宽度
outer min-content 和 max-content 宽度为表格单元格、列和列组定义。 这些定义中使用的 widthmin-widthmax-width 值是上文定义的 offsets-adjusted 值:
percentage contributions
表格单元格、列或列组的百分比贡献 根据 widthmax-width 的计算值定义,这些计算值为百分比:

min(percentage width, percentage max-width)

如果计算值不是百分比, 则对 width 使用 0%, 对 max-width 使用一个 infinite 百分比。
请注意,min-width 不包含在此计算中。 因此,百分比 min-width 会被 忽略。 由于 width 在表格布局中的作用类似于 min-width, 且列尺寸不能同时基于长度和百分比, 作者不应在 table-internal 盒上使用 min-width, 而应优先仅依赖 width
测试

3.8.3. 计算列度量

本小节定义与表格每一列相关联的三个重要值: 其 min-content width(归属于该列的最小可能宽度), 其 max-content width(如果没有其他约束适用时,将归属于该列的宽度), 其 intrinsic percentage width(该列希望获得的表格宽度百分比,并且最终可能覆盖其 max-content 宽度)。

为了计算这些值,会使用一个迭代算法。 首先,忽略任何跨越多于一列的单元格来计算这些值。 然后,通过逐步考虑跨越更多列的单元格来更新这些值。 当已经考虑了跨越表格所有列的单元格时,该算法结束,并最终确定这些值。

就以固定模式布局时测量列而言, 仅考虑在表格第一行中起始的单元格 (在重新排序表头和表尾之后), 如果有的话。 此外,单元格的 min-content 和 max-content 宽度 被视为零,除非它们直接被指定 为 length-percentage,在这种情况下,它们会 基于表格宽度解析(如果表格宽度是确定的,否则使用 0)。

就计算单元格的 outer min-content width 而言, 表格单元格中其宽度依赖于父单元格宽度百分比的后代 会被视为具有 auto 宽度。测试用例 测试用例

基于 span 至多为 1 的单元格的列 min-content width
以下各项中的最大值:
基于 span 至多为 1 的单元格的列 max-content width
以下各项中的最大值:
基于 span 至多为 1 的单元格的列 intrinsic percentage width
以下各项的百分比贡献中的最大值: 每个跨越该列且其 colSpan 为 1 的单元格、 其对应 table-column(如果有),以及 其对应 table-column-group(如果有)
基于 span 至多为 N 的单元格的列 min-content width(N > 1)
基于 span 至多为 N-1 的列 min-content width 与该列中 colSpan 为 N 的单元格贡献值中的最大值, 其中单元格的贡献值是执行以下步骤得到的结果:
  1. 将基准 min-content width 定义为 该单元格跨越的所有列 基于 span 至多为 N-1 的 max-content 宽度之和。
  2. 将基准 border spacing 定义为 该单元格跨越的任何列的水平 border-spacing 之和, 不包括该单元格起始所在的列。
  3. 单元格的贡献值为以下各项之和:
    • 基于 span 至多为 N-1 的列 min-content width
    • 以下乘积:
      • 以下比率:
        • 该列基于 span 至多为 N-1 的 max-content width 减去该列基于 span 至多为 N-1 的 min-content width,与
        • 基准 max-content width 减去基准 min-content width
        如果该比率未定义,则为零,以及
      • 单元格的 outer min-content width 减去基准 min-content width 和基准 border spacing, 并钳制为至少 0、至多为 基准 max-content width 与基准 min-content width 之间的差
    • 以下乘积:
      • 该列基于 span 至多为 N-1 的 max-content width 与基准 max-content width 的比率
      • 单元格的 outer min-content width 减去基准 max-content width 和基准 border spacing, 如果这是负数则为 0
基于 span 至多为 N 的单元格的列 max-content width(N > 1)
基于 span 至多为 N-1 的 max-content width 与该列中 colSpan 为 N 的单元格贡献值中的最大值, 其中单元格的贡献值是执行以下步骤得到的结果:
  1. 将基准 max-content width 定义为 该单元格跨越的所有列 基于 span 至多为 N-1 的 max-content 宽度之和。
  2. 将基准 border spacing 定义为 该单元格跨越的任何列的水平 border-spacing 之和, 不包括该单元格起始所在的列。
  3. 单元格的贡献值为以下各项之和:
    • 基于 span 至多为 N-1 的列 max-content width
    • 以下乘积:
      • 该列基于 span 至多为 N-1 的 max-content width 与基准 max-content width 的比率
      • 单元格的 outer max-content width 减去基准 max-content width 和基准 border spacing, 如果这是负数则为 0
基于 span 至多为 N 的单元格的列 intrinsic percentage width(N > 1)
如果基于 span 至多为 N-1 的列 intrinsic percentage width 大于 0%, 则基于 span 至多为 N 的列 intrinsic percentage width 与基于 span 至多为 N-1 的列 intrinsic percentage width 相同。

否则,它是该列中 colSpan 为 N 的单元格贡献值中的最大值, 其中单元格的贡献值是执行以下步骤得到的结果:
  1. 从该单元格的百分比贡献开始。
  2. 减去该单元格跨越的所有列基于 span 至多为 N-1 的 intrinsic percentage width。 如果这得到负结果,则将其改为 0%。
  3. 乘以以下比率:
    • 该列的 non-spanning max-content width 与
    • 该单元格跨越的所有列中,基于 span 至多为 N-1 的列 intrinsic percentage width 等于 0% 的列的 non-spanning max-content width 之和。
    但是,如果该比率因为分母为零而未定义, 则改用 1 除以该单元格跨越的、基于 span 至多为 N-1 的列 intrinsic percentage width 等于 零的列数。
列的 min-content width
基于 span 至多为 N 的列 min-content width,其中 N 是表格中的列数
列的 max-content width
基于 span 至多为 N 的列 max-content width,其中 N 是表格中的列数
列的 intrinsic percentage width
以下两项中的较小者:
  • 基于 span 至多为 N 的列 intrinsic percentage width, 其中 N 是表格中的列数
  • 100% 减去表格中所有先前列的 intrinsic percentage width 之和 (当 direction 为 "ltr" 时在更左侧("rtl" 时为右侧))测试用例

将列的 intrinsic percentage widths 总和钳制到最大 100% 意味着表格布局算法在切换列时并非不变。

受约束性
如果某列的对应 table-column-group(如果有)、 其对应 table-column(如果有), 或任何仅跨越该列的单元格 具有一个计算 width, 其值不是 "auto", 且不是百分比,则该列是受约束的。
在本规范的未来修订中,该算法需要考虑 单元格的字符对齐(<string> 值的 text-align 属性)。 这需要(基于 2011年3月9日 css3-text 编辑者草案)分别跟踪 对齐字符串中心之前的列部分和 对齐字符串中心之后的列部分的 max-content 宽度。 对于跟踪 min-content 宽度,有两个选项: 要么不跟踪它们,要么跟踪三个值: 两个值像 max-content 宽度一样用于其中没有断点的任何单元格, 以及第四个值用于其中确实有断点的任何单元格 (因此字符对齐对其不是强制的)。
编辑性。 这里描述从跨列单元格分配宽度的方式是错误的。 对于 min-content 和 max-content 宽度,它应引用 为固有宽度计算而将多余宽度分配给列的规则。
测试

3.9. 可用宽度分配

测试

3.9.1. 计算表格宽度

在决定所有列的最终宽度之前, 有必要计算表格本身的宽度。

如前所述,这通常会是所有列首选宽度之和, 加上任何额外部分。 在这种情况下,宽度分配将使每列获得其首选宽度。 然而,有一些情况中作者显式要求某个其他宽度, 也有一些情况中表格无法获得其所需的宽度。

标题宽度最小值 (CAPMIN)table captionsmin-content contribution 中的最大值。

行/列网格宽度最小值 (GRIDMIN)宽度是 所有列的 min-content width 之和 加上单元格间距或边框。

行/列网格宽度最大值 (GRIDMAX)宽度是 所有列的 max-content width 之和 加上单元格间距或边框。

表格的使用 min-width是 已解析的 min-widthCAPMINGRIDMIN 中较大的值。

表格的使用宽度 取决于列和标题宽度,如下所示:

测试

可分配表格 宽度是 表格的使用宽度 减去总水平边框间距(如果有)。 这是我们将能够分配给各列的宽度。

在此算法中,行(和行组)以及列(和列组)既会约束 其所含单元格的尺寸,也会被这些尺寸约束。 设置列的宽度可能会间接影响行的高度,反之亦然。
测试

3.9.2. 核心分配原则

本节为非规范性内容。

3.9.2.1. 规则

理想情况下,每列都应获得其首选宽度(通常是其 max-content width)。 然而,先前计算出的可分配表格宽度 可能过大或过小,无法实现此结果, 在这种情况下,用户代理必须按照宽度分配算法中的描述, 为各列分配临时宽度。

此算法在确定列的使用宽度时遵循三条规则:

规则 0: 在固定模式中, auto 列和百分比列会被分配零像素的最小宽度,并且 百分比解析遵循一套不同的规则, 其目标是确保像素列始终被分配其首选宽度。

规则 1: 分配首选宽度时, 指定百分比的列优先级高于 指定单位值的列,而指定单位值的列优先级又高于 auto 列。

规则 2: 使用相同尺寸类型的列(百分比列、像素列或 auto 列)遵循相同的分配方法。 例如,它们都获得其 min-content width,或者都获得其 max-content width
此规则有一个例外。 当向百分比列给予其首选百分比宽度时, 如果这会导致尺寸小于其 min-content width, 则该列会改为被分配其 min-content width, 尽管百分比列组整体仍被视为 已分配首选百分比宽度。

规则 3: 分配给所有列的宽度之和应等于可分配 表格宽度

测试
3.9.2.2. 可用尺寸

所有三种类型的列都有以下可能的使用宽度。

  1. min-content width:
    适应该列内容所需的尺寸
  2. min-content width + delta:
    介于 min-content 宽度和首选 宽度之间的值
  3. 首选宽度:
    为该列指定的尺寸, 或在不换行的情况下适应该列内容所需的尺寸
  4. 首选宽度 + delta
    大于首选宽度的值

分配算法定义这些值,并说明何时使用它们。

3.9.3. 分配算法

当表格以给定的使用宽度布局时, 每列的使用宽度必须按如下方式确定, 最终还要考虑对此算法的变更,这些变更适用于固定模式

首先,为表格的每一列分配一个尺寸类型

然后,按尺寸类型为各列分配有效的尺寸方法,得到以下 sizing-guesses:

  1. min-content sizing-guess 是一组列宽分配,其中 每列都被分配其 min-content width。
  2. min-content-percentage sizing-guess 是一组 列宽分配,其中:
    • 每个 percent-column 被分配以下两项中的较大者:
      • 其 intrinsic percentage width 乘以可分配宽度,以及
      • 其 min-content width。
    • 所有其他列都被分配其 min-content width。
  3. min-content-specified sizing-guess 是一组 列宽分配,其中:
    • 每个 percent-column 被分配以下两项中的较大者:
      • 其 intrinsic percentage width 乘以可分配宽度,以及
      • 其 min-content width
    • 任何其他受约束列被分配其 max-content width
    • 所有其他列都被分配其 min-content width。
  4. max-content sizing-guess 是一组列宽分配,其中:
    • 每个 percent-column 被分配以下两项中的较大者:
      • 其 intrinsic percentage width 乘以可分配宽度,以及
      • 其 min-content width
    • 所有其他列都被分配其 max-content width。
注意:

如果可分配 表格宽度小于或等于 max-content sizing-guess, 则列的使用宽度必须是两个相邻 sizing-guesses 的线性组合(权重之和为 1), 这两个 sizing-guesses 的宽度总和界定了可用宽度。

否则,列的使用宽度是从 max-content sizing-guess 开始,并根据将多余宽度分配给列(用于使用宽度)的规则, 将多余宽度分配给表格各列所得的结果。

下列示意图以另一种方式描述该算法, 以便更容易理解。

图例

尺寸算法: 表格的每个图形都表示一种确定列尺寸的方式。 左侧四种情况是规范中上文描述的 sizing-guesses:min-contentmin-content-percentagemin-content-specifiedmax-content。 右侧情况是可用尺寸与四种 sizing-guesses 中任一种都不完全匹配时所需的插值。

尺寸方法的选择: 尺寸方法选择始终从 min-content sizing-guess(左上)开始, 然后通过比较可用宽度与当前使用的方法所消耗的宽度继续。 绿色箭头表示如果应用当前方法后还有额外空间要分配, 你应遵循的方向。 红色箭头表示如果应用当前方法分配了过多空间,需要回退时 你应遵循的方向。

列类型: 每种列类型(auto、px、%)在示意图中都有自己的颜色(黄色、 蓝色、橙色)。 在插值中: 从其在先前 sizing-guess 中的尺寸收缩的列会重新绘制为红色,而 从其在先前 sizing-guess 中的尺寸扩展的列会重新绘制为绿色。

[see-caption-below]
宽度分配算法概览。非规范性。
3.9.3.1. 固定模式下宽度分配的变化

以下对前述算法的变更适用于固定模式

测试
3.9.3.2. 将多余宽度分配给列

将多余宽度分配给列的规则可以通过 两种方式调用:

这两种情况的规则大体相同,但存在细微差异。

本节剩余部分使用术语 已分配宽度来指代正在被分配的这些宽度之一, 而 多余宽度 用来指代正在分配的宽度 超过其要分配到的列的已分配宽度之和的量。

  1. 如果存在非受约束列,这些列具有 intrinsic percentage width 为 0% 且 max-content width 非零的起始单元格(也就是本规则允许增长的列), 则本规则允许增长的列的已分配 宽度 会按 max-content width 的比例增加, 使总增加量等于多余宽度
  2. 否则,如果存在非受约束列,这些列具有 intrinsic percentage width 为 0% 的起始单元格(也就是本规则允许增长的列, 由于前一条规则,它们必须具有零 max-content width), 则本规则允许增长的列的已分配 宽度 会按相等的量增加, 使总增加量等于多余宽度
  3. 否则,如果存在 intrinsic percentage width 为 0% 且 max-content width 非零的受约束列(也就是本规则允许增长的列,由于 其他规则,它们必须具有起始单元格), 则本规则允许增长的列的已分配 宽度 会按 max-content width 的比例增加, 使总增加量等于多余宽度
  4. 否则,如果存在 intrinsic percentage width 大于 0% 的列(也就是本规则允许增长的列,由于 其他规则,它们必须具有起始单元格), 则本规则允许增长的列的已分配 宽度 会按 intrinsic percentage width 的比例增加, 使总增加量等于多余宽度
  5. 否则,如果存在任何这样的列, 则所有具有起始单元格的列的已分配 宽度 会按相等的量增加, 使总增加量等于多余宽度
  6. 否则, 所有列的已分配 宽度 会按相等的量增加, 使总增加量等于多余宽度
当表格以固定模式布局时,这些规则不适用。 在这种情况下,改用以下更简单的规则:
测试

3.10. 可用高度分配

测试

3.10.1. 计算表格高度

?测试用例 ?测试用例 ?测试用例

表格的高度是各行高度之和加上任何单元格间距或边框。 如果表格具有一个值不是 auto 的 height 属性,则它被视为 table grid 的最小高度, 如果各行的整体最小 高度最终小于这个数值,则它最终会分配给各行的高度。 如果它们的整体尺寸最终大于指定的 height,则指定的 height 将没有效果。

行的最小高度是以下各项中的最大值:

ROWMIN 定义为 首次行布局遍历之后各行最小高度的总和。

因此,要计算表格的高度, 有必要对其所有行执行一次首次遍历布局, 计算所有最小行高度加上间距/边框的总和, 并返回该值与 table-root 指定的 height(min-height)中的较大者。

一旦确定表格高度, 行通常会进行第二次布局遍历(此时其单元格高度不再被视为 auto), 然后会发生高度分配,以调整其高度,使其整体满足 表格高度, 随后 table-cell 后代可能会进行第二次布局(其中 它们的百分比高度会被解析)。

测试

3.10.2. 行布局(第一遍)

行的最小高度(不含与跨越相关的高度分配) 定义为一个假想 linebox 的高度, 该 linebox 包含起始于该行的单元格, 并且跨越多行的单元格被视为具有 0px 高度 (但具有其正确基线)。 在此假想 linebox 中,单元格高度被视为 auto, 其宽度(包括边框和内边距)会被强制为其所跨越列的宽度和内部间距, 但其其他属性会保留。

为了计算此高度, 表格单元格中其高度依赖于父单元格高度百分比的后代(见下节), 如果它们的 overflow 被设为 visiblecliphidden,或者如果它们是替换元素, 则会被视为具有 auto 高度; 如果不是,则为 0px 高度。测试用例 !!测试用例

对于其百分比高度因上述规则而被忽略的 table-cell 后代, 一旦高度分配结束,就会对 table-cell 内容进行第二次布局遍历, 以尝试正确考虑此尺寸(见下节)

单元格的基线 定义为 单元格中第一个流内行盒的基线,或者 单元格中第一个流内 table-row 的基线, 以较先出现者为准。 如果不存在这样的行盒或 table-row, 则基线是单元格盒内容边缘的底部。

测试

以下是在实践中的工作方式:

td { vertical-align: baseline; outline: 3px solid silver; }
img { float: left; clear: left; width: 32px; height: 32px; }
img[title] { float: none; }

<table><tr>
  <td>基线</td>
  <td>基线<table><tr><td>之后</td></tr></table></td>
  <td><table><tr><td>基线</td></tr></table>之后</td>
  <td><table align=right><tr><td>之前</td></tr></table><p>基线</p></td>
  <td><img src="http://w3.org/favicon.ico"><p>基线</p></td>
  <td><img src="http://w3.org/favicon.ico" title="Baseline"/><br/><img src="http://w3.org/favicon.ico" title="After"></td>
  <td><img src="http://w3.org/favicon.ico"><img src="http://w3.org/favicon.ico"><!--基线--></td>
</tr></table>
[see-caption-below]
此示例在合规 浏览器中的渲染

为了寻找基线,具有 滚动机制(见 overflow 属性)的流内盒 必须被视为滚动到其原点位置。

单元格的基线最终可能位于其底部边框下方, 见下例。

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

div { height: 0; overflow: hidden; }

<table>
<tr>
<td>
<div> 测试 </div>
</td>
</tr>
</table>

每个表格单元格的 vertical-align 属性决定其在行内的对齐方式。 每个单元格的内容都有基线、顶部、中部和底部,行本身也是如此。

在表格单元格的上下文中,vertical-align 的值具有以下含义:

baseline 单元格的基线与其跨越的第一行中其他单元格的基线对齐 (见单元格基线的定义)。
top 单元格盒的顶部与其跨越的第一行的顶部对齐。
bottom 单元格盒的底部与其跨越的最后一行的底部对齐。
middle 单元格的中心与其跨越的各行的中心对齐。
... 其他值不适用于单元格;该单元格改为按基线对齐。

所有具有 'vertical-align: baseline' 的单元格中, 单元格盒顶部到基线之间的最大距离 用于设置该行的基线。 如果某行没有任何具有 'vertical-align: baseline' 的单元格, 则该行的基线是该行中最低单元格的底部内容边缘。

table-root 的 基线是其第一行的基线(如果有)。 否则,它是 table-root 的底部内容边缘。

测试用例 !!测试用例

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

此示例展示前述算法如何创建一行的各种对齐线。

[see-caption-below]
示意图展示 vertical-align 的各种值对表格单元格的影响。 单元格盒 1 和 2 按其基线对齐。单元格盒 2 在基线上方具有最大高度, 因此它决定该行的基线。

由于在行布局期间,该行中单元格的指定高度被忽略, 且跨越多于一行的单元格尚未被正确确定尺寸, 它们的高度最终需要分配给它们所跨越的行集合。 这是通过运行与列 测量相同的算法完成的, 其中 span=1 值(对于 min-content)会使用以下各项中的最大值进行初始化: 前一行布局所得高度、 对应 table-row 上指定的高度(如果有), 以及仅跨越该行的单元格上指定的最大高度 (算法从在该分配之上考虑 span 为 2 的单元格开始)。

编辑性。将 § 3.8.3 计算列度量的相关章节导入这里。

因应用这些步骤而尺寸增加的行 通过降低其底部进行调整。

其位置依赖于任何已更新行底部的单元格 必须在其各自的行中重新正确定位。

此时,小于其所跨越行的整体高度的单元格盒 会获得额外的顶部和/或底部内边距, 使其内容不会垂直移动, 但其顶部/底部边缘会与其所跨越的第一行/最后一行的边缘相接。

请注意,定义在行组上的高度会被此 算法忽略
测试

3.10.3. 行布局(第二遍)

一旦确定了表格高度,如有必要,将执行第二次行布局遍历, 以通过考虑行/单元格指定 height 中使用的百分比, 为表格行分配正确的最小高度。 除此之外,第一遍行布局的所有指令都适用(见上文)

请注意,因此此第二遍最小高度仍然会按照第一遍的建议 处理 table-cell 后代的百分比高度(见 上文)。 因此,不需要重新布局 table-cells 的内容来计算新的行最小 高度。 如有必要,table-cell 内容稍后会在 表格高度分配结束之后重新布局(见下文)

然后,如果第二遍之后表格行的新高度之和 不同于填充先前确定的表格高度所需的值, 则应用下文定义的高度分配算法 (要么通过在第一遍最小高度和第二遍最小高度之间取中间尺寸来收缩行, 要么将所有行的高度增加到超过其第二遍最小高度,以填充可用空间; 无论哪种情况,这都不会影响行的基线)。

3.10.4. 核心分配原则

编辑性。TODO。对于 当前提案,跳到 § 3.10.5 分配算法
关于高度分配的调查

3.10.5. 分配算法

第一步是为每一行赋予其基础尺寸和参考尺寸。

基础尺寸是如果表格没有指定高度时 它本会获得的尺寸 (即评估 ROWMIN 时分配给它的尺寸)。

参考尺寸是以下各项中的最大值

第二步是基于这些尺寸计算每一行的最终高度。

如果表格高度等于或小于参考尺寸之和, 则分配给每一行的最终高度将是 基础尺寸和参考尺寸的加权平均值, 该平均值会产生正确的总高度。

否则,如果表格拥有任何“auto-height”行 (即尺寸仅由其内容尺寸决定,且没有任何指定高度的行), 则每个非 auto-height 行获得其参考高度, 而 auto-height 行获得其参考尺寸加上某个增量, 该增量等于达到指定表格高度所缺少的高度 除以这种行的数量。

否则,所有行都获得其参考尺寸加上某个增量, 该增量等于达到指定表格高度所缺少的高度 除以行数。

其位置依赖于任何已更新行底部的单元格 必须在其各自的行中重新正确定位。

此时,小于其所跨越行的整体高度的单元格盒 会获得额外的顶部和/或底部内边距, 使其内容不会垂直移动, 但其顶部/底部边缘会与其所跨越的第一行/最后一行的边缘相接。

测试

3.10.6. 表格单元格内容布局(第二遍)

一旦 table-height 分配结束,并且行高度加上间距/边框之和等于 表格高度, 那些包含了后代的 table-cells 的内容必须进行 第二次布局遍历,如下所定义;这些后代的百分比高度此前在第一遍行布局规则中被忽略 或被视为 0px(见上文)

注意,这意味着 UA 要么需要跟踪 table-cell 的任何直接子元素属性中百分比的使用情况,包括(但不限于) 水平流中的 heightmin-height 属性,以及 垂直流中的 widthmin-width 属性, 要么需要在所有情况下对 table-cell 内容执行此第二次布局遍历。

解析 table-cell 内容中的百分比高度: 一旦表格和行的最终尺寸已确定, 在高度分配结束之后, table-cells 的内容也必须经历第二次布局遍历, 其中,如果适当,基于百分比的高度这次会相对于 其父单元格的使用高度进行解析。

适合解析 table-cell 直接子元素上的 百分比高度,条件是该单元格被认为显式指定了其高度, 或者该子元素是绝对定位的,见 CSS 2

出于兼容性原因,进一步澄清如下: 如果单元格的计算高度是一个长度,或者 其 table-root 祖先的计算高度是长度或百分比, 则该单元格被认为显式指定了其高度, 无论该百分比是否表现为 auto

为了阐明前述陈述,以下是基于所使用值得出的 "A" div 高度表:
<section style="height: var(--wrapper-height)">
  <table style="height: var(--table-height)">
    <tr>
      <td style="height: var(--table-cell-height)">

        <div style="height:100%; background:yellow">A</div>

      </td>
      <td style="height: var(--other-table-cell-height)">

        B<br>C

      </td>
    </tr>
  </table>
</section>
--table-cell-height --table-height 结果
<length> <any> 100%
<any> <length> 100%
<any> <percentage> 100%
auto auto auto
<percentage> auto auto

注意,--other-table-cell-height--wrapper-height 都不会影响 算法结果。

本规范的先前版本错误地说明,当表格具有百分比高度时, 会考虑 --wrapper-height, 但当某个实现落地后出现了兼容性问题,于是该行为随后被特殊处理。

此第二次布局遍历(其中高度百分比会被解析) 可能会使某些单元格内容溢出其父单元格, 例如,如果所使用的所有百分比之和超过 100%。 这是有意设计的。
测试

3.11. 单元格、标题和其他表格内部盒的定位

测试

我们需要就 visibility:collapse 的作用达成决议。[Issue #478]

一旦表格网格中每列的宽度和每行的高度都已确定, 该算法的最后一步就是为每个 table-internal 盒分配其最终位置。

下面计算出的 width/height/left/top 定义了 CSS 布局盒的尺寸, 这意味着它们可通过 CSSOM-VIEW 中定义的 offset* 属性访问 (目前仅限于可获得对应 HTMLElement 引用的 css 盒)。

然后调整 table-wrapper 盒 的尺寸,使其包含所有 table-non-root 盒的 margin box, 以及 table-root 的 border-box。

这里定义的位置是 table-wrapper 预留空间内部的子项位置, 该空间只排除其外边距。 这是因为表格标题位于 table-root 的 border-box 区域之外。

表格内任何 caption-side 为 "top" 的 table-caption 的位置,定义为满足以下条件的矩形:

表格内任何 table-cell、table-track 或 table-track-group 盒的位置, 定义为满足以下条件的矩形:

提醒: 对于 table-track 和 table-track-group 盒, 与分组方向相反方向的所有轨道都被视为已跨越。 例如,table-header-group 被视为跨越所有列, 而 table-column-group 被视为跨越所有行。
上述公式考虑了 border-spacing,这些公式的效果 可能不会立刻显而易见,因此下面给出这些公式的几个性质:

表格内任何 caption-side 为 "bottom" 的 table-caption 的位置,定义为满足以下条件的矩形:

单元格溢出: 如果表格以固定模式布局, 如果某些单元格的内容在第二次布局遍历期间增长得超过了单元格, 或者如果可见单元格所跨越的某些轨道被认为不可, 则某些单元格的内容可能会超出可用空间, 并导致溢出。 这种溢出应当表现得完全就像该单元格是一个绝对定位的 display:block 盒, 并具有适当的对齐,以保持其内容相对于其 inline-start block-start 角(通常为左上角)的位置。!测试用例 !测试用例 测试用例
可见轨道: 就本算法而言,如果列或行对应的 table-track 以及其 table-track-group 父级(如果有)均未将 visibility 设为 collapse,则该列或行被认为是一个 可见 轨道
A table with a caption above it, showing how the caption margins are totally nested inside the table margins, but are outside the border-box of the table nonetheless.
带有顶部标题的表格示意图。
~测试用例 !!测试用例 !!测试用例 !!测试用例 测试用例

4. 绝对定位

4.1. 以 table-root 作为包含块

如果绝对定位元素的包含 块table-wrapper 盒生成, 则该包含块对应于表格外边距所应用到的区域, 包括绘制表格边框的区域以及任何 table-caption 的外边距区域。 偏移属性(top/right/bottom/left) 随后像通常一样,表示从此 containing block 的相应边缘向内的偏移。

绝对定位发生在 table 及其流内内容布局之后, 且不会对任何表格网格轨道的尺寸作出贡献, 也不会以任何方式影响表格网格的大小/配置。

下图展示了相对于表格绝对定位的盒 应如何渲染。

黄色区域是表格内容边缘,黄色箭头表示表格外边距。
绿色区域是表格标题,绿色箭头表示标题外边距。
蓝色区域是表格背景区域, 深蓝色区域是表格边框区域。
黑色区域是相对于表格定位的后代, 箭头表示 top/left/bottom/right 位移。
[see-caption-above]
测试

4.2. 以 table-internal 作为包含块

如果绝对定位元素的包含 块table-internal 生成, 则该包含块对应于从布局期间会分配给该盒的区域的左上角开始的区域, 但其尺寸会计算为:如果所有轨道都被视为可见(无论某些盒上是否将 visibility 设为 collapse),布局期间会分配给该盒的 区域所具有的尺寸, 并按适用情况不包括边框和内边距。

这样做是为了让隐藏列不会触发绝对定位盒中的布局, 且被裁剪的内容看起来不会移动。!!测试用例 !!测试用例

偏移属性(top/right/bottom/left) 随后像通常一样,表示从此包含块的相应边缘向内的偏移。

这仅在 Firefox 中有效。不过,它会让将来实现 position:sticky 更容易。[Chrome bug] [Interop risk: Firefox bug] [Issue #858]

测试

4.3. 以 table-internal 盒作为非包含块父级

绝对定位盒的非包含块父级唯一影响,是在 top+bottom 和/或 left+right 最终均为 auto 时, 定义其静态位置。

对于 table-cells,绝对定位内容像通常一样按块布局规则定位。

由于表格修正, 不可能创建一个绝对定位盒, 使其成为非 table-cell 的 table-internal 盒的子级 (更多细节见关于 float 和 position 的注释)。

5. 渲染

测试

5.1. 单元格绘制顺序

表格单元格像通常一样按 DOM 顺序绘制在 table-root 中, 与单元格最终实际绘制的位置无关。

5.2. 空单元格渲染(边框分离模式)

名称: empty-cells
值: show | hide
初始值: show
适用于: table-cell
继承:
百分比: 不适用
计算值: 指定的关键字
规范顺序: 按语法
动画类型: 离散
测试

在 边框合并模式中, 此属性没有效果。

在 边框分离模式中, 当此属性的值为 hide 时, 不会在空单元格周围/背后绘制边框或背景。

空单元格是一个 table-cell,它既不包含:

我们能否简化 empty-cells:hide?[Issue #605]

例如,考虑以下标记和 css:

<table>
  <td><span></span></td>
  <td></td>
  <td><span></span></td>
</table>
table {
  width: 500px; height: 300px;
  empty-cells: hide;
}

table { background: black; border: 10px solid black; }
td { background: white; }

table { border-spacing: 0px; }
td { padding: 0; }

此代码片段的正确渲染如下所示:

[see-caption-below]
三列的渲染,其中中间一列被 empty-cells:hide 隐藏

5.3. 绘制背景和边框

5.3.1. 绘制表格背景和边框

与其他盒类型不同,table 和 inline-table 盒 不会围绕其整个 client rect 绘制背景和边框。 实际上,表格标题会在视觉上定位在表格外边距和其边框之间, 这意味着需要修改应用于 table-root 的各种效果的绘制区域。

绘制区域:

这不会影响这些概念的其他用途,例如绝对 定位

!测试用例

测试
5.3.1.1. 边框合并模式中的变化

当表格以边框合并模式布局时, 其边框和其 table-cells 的边框的渲染会被修改。 以下规则描述其修改方式。

如果§ 5.3 绘制背景和边框中定义的背景和边框绘制规则 未被覆盖,则仍然适用。

table-root 的边框 在边框合并模式中不会绘制, 除非设置了 border-image 属性。

在后一种情况下,边框会被绘制得好像表格边框是其使用值指定大小的两倍, 且好像该多出的部分渲染在 table-root 的内边距区域内。

即使它们不由表格绘制,表格边框仍然在布局中占据其空间。 单元格会渲染这些共享边框

测试

5.3.2. 绘制单元格背景

缺失单元格修正步骤添加的匿名 table-cells 不会渲染其任何背景。

除了其自身的 background 之外,table-cell 盒还会 渲染其所属的 table-tracktable-track-group 盒的背景。 这实际上不同于简单地继承它们的背景, 因为 background-originbackground-size 计算实际上会在分组盒的边界上完成, 而不是在单元格的边界上完成。

为了寻找每个表格单元格的背景, 可以将不同的表格盒理解为处于六个叠加层上。 在某一层中设置的背景,只有当其上方的各层具有透明背景时 才会可见。

[see-caption-below]
表格层的示意图。
  1. 表格背景由表格渲染, 且不影响单元格背景。
  2. 单元格绘制的第一个背景是其起始所在 table-column-group 的背景(如果有)。 就背景定位而言, 预期一个列组会占据在行/列网格中单个单元格可能占据的最大区域, 同时起始于该列组且不进入任何不属于该列组的列。
  3. 单元格绘制的第二个背景是其起始所在 table-column 的背景(如果有)。 就背景定位而言, 预期一个列会占据在行/列网格中单个单元格可能占据的最大区域, 同时起始于该列且不进入任何其他列。
  4. 单元格绘制的第三个背景是其起始所在 table-row-group 的背景(如果有)。 就背景定位而言, 预期一个行组会占据在行/列网格中单个单元格可能占据的最大区域, 同时起始于该行组且不进入任何不属于该行组的行。
  5. 单元格绘制的第四个背景是其起始所在 table-row 的背景(如果有)。 就背景定位而言, 预期一个行会占据在行/列网格中单个单元格可能占据的最大区域, 同时起始于该行且不进入任何其他行。
  6. 单元格绘制的第五个背景是其自身背景。 这是所有背景渲染完毕后显示在最上方的背景。

如上图所示,虽然所有行包含相同数量的单元格, 但并非每个单元格都可能具有指定内容。在边框分离模式中,如果它们的 empty-cells 属性值为 hide, 则这些空单元格完全不会渲染, 就像在它们上指定了 visibility: hidden 一样, 从而让表格背景透出。

测试

5.3.3. 绘制单元格边框

在边框分离模式中,表格单元格的边框像通常一样渲染。

5.3.3.1. 边框合并模式中的变化

table-cell 的边框 在边框合并模式中渲染时, 就好像单元格边框是其使用值指定大小的两倍, 且好像该多出的部分渲染在单元格的外边距区域中, 并附加约束: 对于边框中不位于表格任一边缘的每一侧, 该边框实际上会按其真实使用值定义的 border-box 绘制区域进行裁剪, 除非设置了 border-image 属性。

如果应用前述裁剪行为会导致以非整数设备像素数量裁剪边框, 浏览器可以决定改为通过向上取整裁剪区域的 x 值和 y 值, 将裁剪区域吸附到设备像素。 向上取整这些值可确保在普通书写模式中, 在多个单元格之间获得有争议像素的单元格实际上是最左上方的那个, 按照本规范,它比其他单元格具有更高优先级。§ 5.1 单元格绘制顺序§ 3.7.1.1 合并 边框的冲突解决算法

测试

5.3.4. 边框样式(边框合并模式)

border-style 的某些值对于边框合并模式中的表格 具有不同于通常情况的含义。 这些定义会覆盖 border-style 值的默认行为。

hidden

none 相同,但还会抑制任何其他边框(见 § 3.7.1.3 边框样式的优先级)。

inset

ridge 相同。

outset

groove 相同。

5.4. visibility: collapse 的渲染

当表格部分设置了 visibility: collapse 时,其渲染方式会根据它是在 table-cell、跨越的 table-cell, 还是在 table-track/table-track-group 上而有所不同。

测试

5.4.1. 渲染 visibility: collapse 的表格单元格

如 CSS 2.2 所述,如果 table-cell 的 visibility 被设为 collapse,则其渲染方式与 设置了 visibility: hidden 相同。

当你在包含 table-cell 的 table-row 上设置 visibility:collapse 时,就会发生这种情况。 如果你想隐藏一行,但继续显示其中跨越其他行的单元格, 请在这些单元格上设置 visibility:visible,以防止它们继承其值。

如果 table-cell 跨越多于一个 table-track, 并且这些 table-track 中至少有一个被设为 visibility: collapse, 则将内容裁剪到该 table-cell 的 border-box。这意味着该单元格左上角 (rtl 中为右上角)的内容会继续显示, 无论该单元格所跨越的哪个轨道被折叠。

5.4.2. 渲染 visibility: collapse 的 table-track 或 table-track-group

table-tracktable-track-group 具有 visibility: collapse 时, 给定 table-tracktable-track-group 内单元格贡献的所有背景、边框或轮廓, 会继续绘制在未被完全折叠的单元格上 (因为它们跨越了多个轨道)。
测试

6. 分片

6.1. 跨 fragmentainer 断开

在对表格进行分片时,用户代理必须尝试 保持表格行不被分片, 如果跨越该行的单元格没有跨越任何后续行,并且 它们的高度至少比 fragmentainer 的高度和宽度都小两倍。 其他行称为 可自由分片

当表格无法完全放入一个 fragmentainer 中, 至少有一行确实完整放入了该 fragmentainer, 并且第一个无法放入该 fragmentainer 的行不是可自由分片时。 用户代理必须插入一些垂直间隙, 插在位于溢出点之前和溢出点处的行之间, 使这两行最终被分隔到兄弟 fragmentainer 中。 如果分片需要重复页眉和页脚,并且页脚被重复, 那么页脚必须紧跟在该 fragmentainer 中的最后一行之后, 并且垂直间隙必须插入在重复页脚之后。

[见下方说明]
跨两页分片的表格的预期渲染

当没有任何行能完整放入当前 fragmentainer, 或者第一个无法放入 fragmentainer 的行是可自由分片时, 用户代理必须把 fragmentainer 中所有剩余高度分配给 该行的单元格,并在每个单元格中独立地放入尽可能多的内容, 然后断到下一个片段,并从每个单元格上一个片段中停止的位置 开始其内容(顶部边框不得在延续片段中重新绘制)。

[见下方说明]
包含跨两页分片的高行的表格的预期渲染

break-beforebreak-after 应用于 table-row-grouptable-row 盒时, 用户代理必须插入一些垂直间隙, 插在位于断点之前和之后的行之间, 使这两行最终按该属性值的要求 被分隔到兄弟 fragmentainer 中。 如果分片需要重复页眉和页脚,并且页脚被重复, 那么页脚必须紧跟在该 fragmentainer 中的最后一行之后, 并且垂直间隙必须插入在重复页脚之后。

6.2. 跨页重复页眉

当把文档渲染到分页媒体中时, 用户代理必须在表格跨越的每一页上重复页眉行页脚行, 如果该页面是表格的 fragmentainer, 如果页眉/页脚应用了 avoid break-inside, 如果这样做所需的高度小于 页面高度的二分之一 (页眉行最多四分之一,且 页脚行最多四分之一),并且 如果这不会导致某一行在该页面上显示两次。

当页眉行被重复时,用户代理必须 留出空间,并在需要时渲染表格顶部边框。 页脚行和表格底部边框同理。

[见下方说明]
带有跨两页分片的页眉和页脚的表格的预期渲染

用户代理可以决定将此行为扩展到更多分片上下文, 例如除跨页之外,还跨列重复页眉/行。 渲染静态文档的用户代理更可能采用此行为, 但规范并不要求这样做。

7. 安全考虑

使用 CSS Tables 不会带来任何需要缓解的安全风险。

8. 隐私考虑

使用 CSS Tables 不会带来任何需要缓解的隐私风险。

9. 正在跟踪的 bug 列表

本节不是规范性的。

10. 附录

10.1. CSS 与 HTML 属性之间的映射

HTML4 的默认样式表展示了其模型如何映射到 css 属性和值:

一些 CSS 扩展已用于无法映射到当前 CSS 构造的约束
table    { display: table }
thead    { display: table-header-group }
tbody    { display: table-row-group }
tfoot    { display: table-footer-group }
tr       { display: table-row }
td, th   { display: table-cell }
colgroup { display: table-column-group }
col      { display: table-column }
caption  { display: table-caption }
table, thead, tbody, tfoot, tr, td, th, colgroup, col, caption { box-sizing: border-box; }
thead, tfoot { break-inside: avoid }

table {
  box-sizing: border-box;
  border-spacing: 2px;
  border-collapse: separate;
  text-indent: initial;
}

thead, tbody, tfoot, table > tr { vertical-align: middle; }
tr, td, th { vertical-align: inherit; }

td, th { padding: 1px; }
th { font-weight: bold;  }

table, td, th { border-color: gray; }
thead, tbody, tfoot, tr { border-color: inherit; }



table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border: 1px solid inset;
}


table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) {
  border-collapse: collapse;
  border-style: hidden;
}

table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]),
table:is([rules=all i], [rules=rows i], [rules=cols i], [rules=groups i], [rules=none i]) > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border-color: black;
}

table[border=$border] /* if(parseInt($border) > 0) */ {
  border: /*(parseInt($border) * 1px)*/ outset rgb(128, 128, 128);
}
table[border=$border] > :is(thead,tbody,tfoot) > tr > :is(th,td) /* if(parseInt($border) > 0) */ {
  border: 1px inset rgb(128, 128, 128);
}

table[rules=all i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
}
table[rules=rows i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
  border-left: none;
  border-right: none;
}
table[rules=cols i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: 1px solid grey;
  border-top: none;
  border-bottom: none;
}
table[rules=none i] > :is(thead,tbody,tfoot) > tr > :is(th,td) {
  border: none;
}

table[rules=groups i] > :is(thead,tbody,tfoot) {
  border-top-width: 1px; border-top-style: solid;
  border-bottom-width: 1px; border-bottom-style: solid;
}
table[rules=groups i] > colgroup {
  border-left-width: 1px; border-left-style: solid;
  border-right-width: 1px; border-right-style: solid;
}

table[frame=box i], table[frame=border i], table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-style: outset;
}
table[frame=below i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-top-style: hidden;
}
table[frame=above i], table[frame=vsides i], table[frame=lhs i], table[frame=rhs i] {
  border-bottom-style: hidden;
}
table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
  border-left-style: hidden;
}
table[frame=hsides i], table[frame=above i], table[frame=below i], table[frame=rhs i] {
  border-right-style: hidden;
}

table[cellpadding=$x] > :is(thead,tbody,tfoot) > tr > :is(th,td) /* if(parseInt($x)>0) */ {
  padding: /*(parseInt($x) * 1px)*/;
}
table[cellspacing=$x] /* if(parseInt($x)>0) */ {
  border-spacing: /*(parseInt($x) * 1px)*/;
}


table[width=$w] /* if(parseInt($w) > 0) */ {
  width: /*(parseInt($w) * 1px)*/;
}
table[width=$w] /* if($w matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
  width: /*(parseInt($w) * 1px)*/;
}
table[height=$h] /* if(parseInt($h) > 0) {
  height: /*(parseInt($h) * 1px)*/;
}
table[height=$h] /* if($h matches /(+|-|)([0-9]+([.][0-9]+|)|([.][0-9]+))[%]/) */ {
  height: /*(parseInt($h) * 1px)*/;
}


table[bordercolor=$color] {
  border-color: /*parseHTMLColor($color)*/;
}
table[bordercolor] > :is(tbody, thead, tfoot, tr, colgroup, col),
table[bordercolor] > :is(tbody, thead, tfoot) > tr,
table[bordercolor] > :is(tbody, thead, tfoot) > tr > :is(td, th),
table[bordercolor] > tr > :is(td, th)
table[bordercolor] > colgroup > col
) {
  border-color: inherit;
}
table[bgcolor=$color] {
  background-color: /*parseHTMLColor($color)*/;
}
table[align=left i] {
  float: left;
}
table[align=right i] {
  float: right;
}
table[align=center i] {
  margin-left: auto;
  margin-right: auto;
}

caption[align=bottom i] { caption-side: bottom; }
:is(thead,tbody,tfoot,tr,td,th)[valign=top i] {
  vertical-align: top;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=middle i] {
  vertical-align: middle;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=bottom i] {
  vertical-align: bottom;
}
:is(thead,tbody,tfoot,tr,td,th)[valign=baseline i] {
  vertical-align: baseline;
}

:is(thead,tbody,tfoot,tr,td,th)[align=absmiddle i] {
  text-align: center;
}

:is(colgroup,col,thead,tbody,tfoot,tr,td,th)[hidden] {
  visibility: collapse;
}

:is(td,th)[nowrap] { white-space: nowrap; }
:is(td,th)[nowrap][width=$w] /* if(quirksMode && parseInt($w) > 0) */ {
  white-space: normal;
}
测试
此处部分内容来自 WHATWG 规范中关于表格的 HTML 到 CSS 映射的部分。 但是,由于其中包含一些在大多数浏览器中并不成立的内容, 因此这不是简单复制。 因而,对于从一个来源合并到另一个来源的每一处内容,都需要进行调查!

11. (链接 到此处用于缺失章节)

12. 变更

2019 年 7 月 27 日 工作草案以来的重要变更:

一致性

文档约定

一致性要求以 描述性断言和 RFC 2119 术语的组合来表达。规范性部分中的关键词 “MUST”、 “MUST NOT”、“REQUIRED”、“SHALL”、“SHALL NOT”、“SHOULD”、“SHOULD NOT”、 “RECOMMENDED”、“MAY” 和 “OPTIONAL” 应按 RFC 2119 中的描述解释。 但是,为了可读性,这些词在本规范中并不总是以全大写 字母出现。

本规范中的所有文本都是规范性的,除非章节 明确标记为非规范性、示例和注释。[RFC2119]

本规范中的示例以 “for example” 这些词引入, 或者以 class="example" 从规范性文本中分离出来, 如下:

这是一个信息性示例的例子。

信息性注释以 “Note” 这个词开头,并以 class="note" 从规范性文本中分离出来, 如下:

Note,这是一个信息性注释。

建议性条目是规范性章节,其样式用于引起特别注意,并以 <strong class="advisement"> 从其他规范性文本中分离出来,例如 这样: UA 必须提供可访问的替代方案。

测试

与本规范内容相关的测试 可以记录在像这样的“测试”块中。 任何此类块都是非规范性的。


一致性类别

本规范的一致性 定义了三个一致性类别:

样式表
一个 CSS 样式表
渲染器
一个解释样式表语义并渲染 使用它们的文档的 UA
创作工具
一个编写样式表的 UA

如果样式表中所有使用本模块所定义语法的语句 按照通用 CSS 语法和本模块所定义的每个特性的 单独语法都是有效的, 则该样式表符合本规范。

如果渲染器除按相应规范定义解释样式表之外, 还支持本规范定义的所有特性, 正确解析它们并相应地渲染文档, 则该渲染器符合本规范。但是, UA 因设备限制而无法正确渲染文档, 并不会使该 UA 不符合规范。(例如,UA 不 要求在单色显示器上渲染颜色。)

如果创作工具编写的样式表在语法上符合 通用 CSS 语法以及本模块中每个特性的 单独语法,并满足本模块中所描述的样式表的 所有其他一致性要求, 则该创作工具符合本规范。

部分实现

为了使作者能够利用向前兼容的解析规则来 分配回退值,CSS 渲染器必须把任何它们没有可用支持级别的 at-rule、属性、属性值、关键字以及其他语法构造视为无效 (并酌情忽略)。 特别是,用户代理不得在单个 多值属性声明中选择性地忽略不受支持的组件值并遵守受支持的值: 如果任何值被认为无效 (不受支持的值必须如此),CSS 要求整个声明 被忽略。

不稳定和 专有特性的实现

为了避免与未来稳定的 CSS 特性冲突, CSSWG 建议在实现 CSS 的不稳定特性和专有扩展时, 遵循最佳实践

非实验性实现

一旦规范达到候选推荐阶段, 非实验性实现就成为可能,并且实现者应该 发布任何能证明已根据规范正确实现的 CR 级特性的 无前缀实现。

为了建立并维护 CSS 在各实现之间的互操作性, CSS 工作组请求非实验性 CSS 渲染器在发布任何 CSS 特性的无前缀实现之前, 向 W3C 提交实现报告(以及必要时提交用于该实现报告的 测试用例)。提交给 W3C 的测试用例需经 CSS 工作组审查和修正。

关于提交测试用例和实现报告的更多信息 可在 CSS 工作组网站 https://www.w3.org/Style/CSS/Test/ 上找到。 问题应发往 public-css-testsuite@w3.org 邮件 列表。

索引

本 规范定义的术语

由 引用定义的术语

参考文献

规范性参考文献

[COMPOSITING-1]
Chris Harrelson。合成与混合第 1 级。2024 年 3 月 21 日。CRD。URL:https://www.w3.org/TR/compositing-1/
[CSS-BACKGROUNDS-3]
Elika Etemad; Brad Kemper。CSS 背景与 边框模块第 3 级。2024 年 3 月 11 日。CRD。URL:https://www.w3.org/TR/css-backgrounds-3/
[CSS-BORDERS-4]
Elika Etemad; et al. CSS 边框与盒装饰 模块第 4 级。2025 年 7 月 22 日。FPWD。URL:https://www.w3.org/TR/css-borders-4/
[CSS-BOX-4]
Elika Etemad。CSS 盒模型模块第 4 级。2024 年 8 月 4 日。WD。URL:https://www.w3.org/TR/css-box-4/
[CSS-BREAK-3]
Rossen Atanassov; Elika Etemad。CSS 分片模块 第 3 级。2018 年 12 月 4 日。CR。URL:https://www.w3.org/TR/css-break-3/
[CSS-COLOR-4]
Chris Lilley; Tab Atkins Jr.; Lea Verou。CSS 颜色模块 第 4 级。2025 年 4 月 24 日。CRD。URL:https://www.w3.org/TR/css-color-4/
[CSS-DISPLAY-4]
Elika Etemad; Tab Atkins Jr.。CSS Display 模块第 4 级。2025 年 11 月 6 日。WD。URL:https://www.w3.org/TR/css-display-4/
[CSS-GRID-2]
Tab Atkins Jr.; et al. CSS Grid Layout 模块第 2 级。2025 年 3 月 26 日。CRD。URL:https://www.w3.org/TR/css-grid-2/
[CSS-INLINE-3]
Elika Etemad。CSS Inline Layout 模块第 3 级。2024 年 12 月 18 日。WD。URL:https://www.w3.org/TR/css-inline-3/
[CSS-MASKING-1]
Dirk Schulze; Brian Birtles; Tab Atkins Jr.。CSS Masking 模块第 1 级。2021 年 8 月 5 日。CRD。URL:https://www.w3.org/TR/css-masking-1/
[CSS-OVERFLOW-3]
Elika Etemad; Florian Rivoal。CSS Overflow 模块 第 3 级。2025 年 10 月 7 日。WD。URL:https://www.w3.org/TR/css-overflow-3/
[CSS-POSITION-3]
Elika Etemad; Tab Atkins Jr.。CSS Positioned Layout 模块第 3 级。2025 年 10 月 7 日。WD。URL:https://www.w3.org/TR/css-position-3/
[CSS-SIZING-3]
Tab Atkins Jr.; Elika Etemad。CSS Box Sizing 模块 第 3 级。2021 年 12 月 17 日。WD。URL:https://www.w3.org/TR/css-sizing-3/
[CSS-TEXT-4]
Elika Etemad; et al. CSS Text 模块第 4 级。 2024 年 5 月 29 日。WD。URL:https://www.w3.org/TR/css-text-4/
[CSS-TRANSFORMS-1]
Simon Fraser; et al. CSS Transforms 模块第 1 级。2019 年 2 月 14 日。CR。URL:https://www.w3.org/TR/css-transforms-1/
[CSS-TRANSFORMS-2]
Tab Atkins Jr.; et al. CSS Transforms 模块第 2 级。2021 年 11 月 9 日。WD。URL:https://www.w3.org/TR/css-transforms-2/
[CSS-VALUES-3]
Tab Atkins Jr.; Elika Etemad。CSS Values and Units 模块第 3 级。2024 年 3 月 22 日。CRD。URL:https://www.w3.org/TR/css-values-3/
[CSS-VALUES-4]
Tab Atkins Jr.; Elika Etemad。CSS Values and Units 模块第 4 级。2024 年 3 月 12 日。WD。URL:https://www.w3.org/TR/css-values-4/
[CSS2]
Bert Bos; et al. 层叠样式表第 2 级修订版 1(CSS 2.1)规范。2011 年 6 月 7 日。REC。URL:https://www.w3.org/TR/CSS2/
[FILTER-EFFECTS-1]
Dirk Schulze; Dean Jackson。Filter Effects 模块 第 1 级。2018 年 12 月 18 日。WD。URL:https://www.w3.org/TR/filter-effects-1/
[MEDIAQUERIES-5]
Dean Jackson; et al. 媒体查询第 5 级。 2021 年 12 月 18 日。WD。URL:https://www.w3.org/TR/mediaqueries-5/
[RFC2119]
S. Bradner。用于 RFC 中表示 要求级别的关键词。1997 年 3 月。最佳当前实践。URL:https://datatracker.ietf.org/doc/html/rfc2119
[SELECTORS-4]
Elika Etemad; Tab Atkins Jr.。选择器第 4 级。2022 年 11 月 11 日。WD。URL:https://www.w3.org/TR/selectors-4/

资料性参考文献

[CSS-DISPLAY-3]
Elika Etemad; Tab Atkins Jr.。CSS Display 模块第 3 级。2023 年 3 月 30 日。CR。URL:https://www.w3.org/TR/css-display-3/
[CSS-TEXT-3]
Elika Etemad; Koji Ishii; Florian Rivoal。CSS Text 模块 第 3 级。2024 年 9 月 30 日。CRD。URL:https://www.w3.org/TR/css-text-3/

属性索引

名称 初始值 适用于 继承 百分比 动画类型 规范顺序 计算值
border-collapse separate | collapse separate table grid 盒 不适用 离散 按语法 指定的关键字
border-spacing <length>{1,2} 0px 0px border-collapse 为 separate 时的 table grid 盒 不适用 按计算值 按语法 两个绝对长度
caption-side top | bottom top table-caption 盒 不适用 离散 按语法 指定的关键字
empty-cells show | hide show table-cell 盒 不适用 离散 按语法 指定的关键字
table-layout auto | fixed auto table grid 盒 不适用 离散 按语法 指定的关键字

问题索引

从 2.1 开始的 border-collapsing 破坏性变更 [Issue #604]
在折叠边框的协调中更改优先级? [Issue #606]
处于 border collapsing 模式时内在偏移的处理 [Issue #608]
编辑性。 这里描述从 colspan 单元格分配宽度的方式是错误的。 对于 min-content 和 max-content 宽度,它应引用 为内在宽度计算向列分配多余宽度的规则。
编辑性。将 § 3.8.3 计算列度量的相关章节导入这里。
编辑性。TODO。对于当前提案,跳到 § 3.10.5 分配算法
我们需要就 visibility:collapse 的作用达成决议。 [Issue #478]
这只在 Firefox 中有效。不过,它会让未来实现 position:sticky 更容易。 [Chrome bug] [互操作风险:Firefox bug] [Issue #858]
我们能否简化 empty-cells:hide? [Issue #605]
我们是否应该通过说明单元格只绘制 visibility:visible 分组元素的背景 来隐藏 row-group 背景?