先绘制完整网格,为每个合并单元格指定一个矩形,并且只在这些矩形的起始位置编写单元格,即可规划具有交错跨度的 HTML 表格。本指南将通过一个示例,带你在 TextEdit 中创建表格并在 Mac 上预览。
编写单元格前先定义网格
任务是构建一个包含五列的表格,其中有分组列标题、一个同时跨越行和列的单元格,以及另一个跨越不同行数的单元格。以下标签和内容仅作示例:它们表示按槽位排列的中性节点块。
HTML 表格用于表示多维数据。其单元格必须覆盖表格网格,且彼此不能重叠。如果你想实现的只是将无关的方框排列在页面上,HTML 标准建议作者改用 CSS Grid 等布局工具。这里每个块都与其行标题和列标题有明确关系,因此适合使用表格。HTML Standard: The table element。
先列出表格中任何位置出现的最小列。本例中的列为 Slot、Node A、Node B、Node C 和 Note。Nodes 标题会覆盖其中三列;它本身不会新增一列。
两个跨度属性统计单元格覆盖的完整范围,包括其起始位置。因此,colspan="2" 覆盖两列,而 rowspan="2" 覆盖两行。两者同时使用会创建一个二乘二的矩形。省略跨度时,默认值为一。MDN: The Table Data Cell element。
“交错”描述的是这些矩形如何拼合。每个单独的单元格仍然覆盖一个矩形范围;单个单元格不能绕过另一个单元格弯曲。可以把它想成在方格纸上放置带标签的矩形。
为每一行制作槽位台账
使用展开后的规划表,通过重复标签显示一个合并单元格覆盖的范围。台账中的重复不表示要在 HTML 中重复编写该单元格。表头部分有两行,表体部分有四行。
| 规划行 | 第 1 列 | 第 2 列 | 第 3 列 | 第 4 列 | 第 5 列 |
|---|---|---|---|---|---|
| 表头 1 | Slot | Nodes | Nodes | Nodes | Note |
| 表头 2 | Slot | Node A | Node B | Node C | Note |
| 表体 1 | Slot 1 | Block P | Block P | Block Q | Note X |
| 表体 2 | Slot 2 | Block P | Block P | Block R | Note X |
| 表体 3 | Slot 3 | Block S | Block T | Block T | Note X |
| 表体 4 | Slot 4 | Block U | Block U | Block U | Note Y |
现在记录每个合并矩形的起始位置和尺寸。这里的坐标从 1 开始,并在每个区段内重新计数。
| 单元格 | 起始位置 | 覆盖行数 | 覆盖列数 |
|---|---|---|---|
| Slot 标题 | 表头第 1 行,第 1 列 | 2 | 1 |
| Nodes 标题 | 表头第 1 行,第 2 列 | 1 | 3 |
| Note 标题 | 表头第 1 行,第 5 列 | 2 | 1 |
| Block P | 表体第 1 行,第 2 列 | 2 | 2 |
| Note X | 表体第 1 行,第 5 列 | 3 | 1 |
| Block T | 表体第 3 行,第 3 列 | 1 | 2 |
| Block U | 表体第 4 行,第 2 列 | 1 | 3 |
有了这份台账,棘手的表体第 2 行就容易处理了:Block P 已占据第 2、3 列,Note X 已占据第 5 列。因此,这一行只有 Slot 2 和 Block R 从该行开始,只需要两个单元格元素。
每一行都按以下步骤处理:
- 标记由前面行开始的跨度所占据的位置。
- 找到第一个未占据的列。
- 放置下一个单元格,并标记其完整矩形范围,包括后续行。
- 如果矩形的任何部分与已占据位置重叠,则舍弃该矩形。
- 继续处理,直到五个列位置都已分配。
这是根据标准中的表格模型得出的规划辅助方法。浏览器放置单元格时会跳过已占用的起始位置,但作者仍必须避免矩形重叠。因此,仅统计一行中单元格元素的数量是不够的。HTML Standard: Processing model。
一个实用的行检查方法是:延续占用的列数 + 新起始单元格覆盖的列数 = 五。表体第 2 行有三个延续占用位置和两个新位置。表体第 3 行有一个延续占用位置和四个新位置。除了总数,也要检查它们的实际位置:总数相符仍无法发现重叠位置与空缺位置同时存在的情况。
规划行组和标题关系
将两行表头都放在同一个 thead 中,并将四行表体都放在同一个 tbody 中。单元格不能跨越不同的行组。例如,Block P 不能从一个 tbody 开始,在另一个中结束。标准还规定了表格子元素的顺序:可选的 caption、列组、可选的 thead、表体行,以及可选的 tfoot。HTML Standard: Tables。
本例定义了三个列组:Slot 占一列,Nodes 占三列,Note 占一列。Nodes 标题使用 scope="colgroup";其下级标题使用 scope="col"。W3C 关于不规则表头的指南建议将分组标题与明确的列组结构配合使用。Tables with Irregular Headers。
几何结构和含义需要分别考虑。Block P 覆盖两行槽位和两列节点,因此它关联的标题为 Slot 1、Slot 2、Nodes、Node A 和 Node B。Note X 属于三行槽位和 Note 列。
对于这些合并数据单元格,本例通过在表头单元格中使用 id 值,并在每个数据单元格的 headers 属性中使用以空格分隔的引用,明确指定关联关系。W3C 记录了这种适用于复杂表格的方法,其中表头关系需要明确标识。Tables with Multi-Level Headers。
不要仅仅因为文本相同,就合并彼此独立的值。在这个虚构文档中,Block P 特意表示一个跨越四个位置的单一块。如果每个位置代表不同的观察结果,就应保留各自独立的单元格,以便表格保持这种区分。
在 Mac 上创建完整的 HTML 文件
可以使用 TextEdit 创建本地 HTML 文档。选择 File > New,然后选择 Format > Make Plain Text。粘贴下方完整文档,选择 File > Save,并将文件命名为 span-plan.html。如果系统询问扩展名,选择 Use .html。这些是 Apple 记录的 HTML 创建步骤。Work with HTML documents in TextEdit on Mac。
这是一个完整的独立文档,包含示例内容和样式。它不需要脚本或外部资源。
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Interlocking span plan</title>
<style>
body { font-family: system-ui, sans-serif; margin: 2rem; }
table { border-collapse: collapse; }
caption { text-align: left; font-weight: bold; margin-bottom: 1rem; }
th, td { border: 1px solid #555; padding: 0.75rem; text-align: left; }
thead { background: #eee; }
</style>
</head>
<body>
<table>
<caption>Synthetic node blocks by slot</caption>
<colgroup span="1"></colgroup>
<colgroup span="3"></colgroup>
<colgroup span="1"></colgroup>
<thead>
<tr>
<th rowspan="2" scope="col" id="slot">Slot</th>
<th colspan="3" scope="colgroup" id="nodes">Nodes</th>
<th rowspan="2" scope="col" id="note">Note</th>
</tr>
<tr>
<th scope="col" id="a">Node A</th>
<th scope="col" id="b">Node B</th>
<th scope="col" id="c">Node C</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row" id="s1">Slot 1</th>
<td rowspan="2" colspan="2" headers="s1 s2 nodes a b">Block P</td>
<td headers="s1 nodes c">Block Q</td>
<td rowspan="3" headers="s1 s2 s3 note">Note X</td>
</tr>
<tr>
<th scope="row" id="s2">Slot 2</th>
<td headers="s2 nodes c">Block R</td>
</tr>
<tr>
<th scope="row" id="s3">Slot 3</th>
<td headers="s3 nodes a">Block S</td>
<td colspan="2" headers="s3 nodes b c">Block T</td>
</tr>
<tr>
<th scope="row" id="s4">Slot 4</th>
<td colspan="3" headers="s4 nodes a b c">Block U</td>
<td headers="s4 note">Note Y</td>
</tr>
</tbody>
</table>
</body>
</html>
在 Mac 上用浏览器打开保存的文件。对照台账检查:Block P 应在 Nodes 下的 Node A 和 Node B 列中跨越 Slot 1 和 Slot 2;Note X 应跨越 Slot 1–3;Block T 应只在 Slot 3 中覆盖 Node B 和 Node C。这三项检查可以区分预期的交错模式与仅仅具有矩形外框的表格。
如果在 TextEdit 中重新打开文件时显示的是格式化内容,请选择 File > Open,选中文件,点击 Show Options,然后选择 Ignore rich text commands。Apple 还说明,后续编辑时可以在 TextEdit > Settings > Open and Save 中启用 Display HTML files as HTML code instead of formatted text。Apple’s TextEdit HTML guide。
诊断错误并在保留结构的情况下更新规划
如果结果与规划不符,检查第一个出错的行,以及延续到该行的矩形。在调整间距或样式前,先进行以下检查。
| 问题表现 | 检查内容 | 本例中的修正方法 |
|---|---|---|
| 出现意外的额外列 | 单元格是否被添加到了先前跨度已占用的位置 | 表体第 2 行只包含 Slot 2 和 Block R;删除其中任何填充单元格 |
| Block R 显示在错误的节点下 | Block P 的宽度和高度 | 确认 Block P 同时设置了 rowspan="2" 和 colspan="2" |
| Note X 在 Slot 2 后结束 | 其行数 | 将跨度设为三行 |
| 表头层级没有对齐 | 第一行表头和第二行的单元格数量 | Slot 和 Note 跨两行;第二行表头只包含三个节点标题 |
| 合并单元格缺少标题关联 | 其 headers 引用 |
将所覆盖的每一行、每一列与台账进行对照 |
当某个位置代表实际的空值时,空单元格是合适的。如果某个位置已被跨度单元格占据,就不需要空单元格。MDN 的单元格文档说明,普通单元格会填入可用位置,且跨度不能重叠。MDN: The Table Data Cell element。
对于这个固定示例,请使用明确的正整数行数。特殊值 rowspan="0" 表示当前行组剩余的所有行,因此添加一行可能会扩展该单元格的覆盖范围。只有当“延伸至该组末尾”准确表达预期关系时才使用此值。MDN: Row span behavior。
插入、删除或重新排序行之前,先更新台账。如果在 Slot 1 和 Slot 2 之间插入新行,并且 Block P 应包含该行,就要增加 Block P 的跨度,并将新行标题加入其 headers 列表。还要单独重新考虑 Note X:同一插入也可能改变它的预期覆盖范围。重新排序行时也要进行相同的检查,因为跨度依据文档中的位置。
如果内容无法再构成容易理解的矩形,就应简化呈现方式。W3C 建议,当多个表头层级使单个表格难以理解时,可以考虑拆分成较小的表格。Tables with Multi-Level Headers。
修改文档时,请将槽位台账放在源码旁边。每次更改都先确定预期矩形,只在起始位置编写单元格,并检查相关标题。这样就能通过可重复的方法,同时保留表格形状及其内容所表达的关系。
来源
- HTML Standard — Tabular data — WHATWG。
<td>: The Table Data Cell element — MDN Web Docs。- Tables with Irregular Headers — W3C Web Accessibility Initiative。
- Tables with Multi-Level Headers — W3C Web Accessibility Initiative。
- Work with HTML documents in TextEdit on Mac — Apple Support。