一个语义正确、无障碍友好的表格必须以为直接子元素(或嵌套在/等合法容器中),且每行含或;表头与数据单元格不可混用,是唯一语义标题,空表也需声明。

一个能被浏览器正确解析、语义清晰、无障碍友好的 <table>,必须包含 <code><tr> 作为直接子元素,且每个 <code><tr> 内至少有一个 <code><th> 或 <code><td>;<code><table> 自身不渲染任何可见内容,空标签会被忽略。
<h3>为什么 <code><tr> 是唯一合法的 <code><table> 直接子元素
<p>HTML 规范明确限定:<code><table> 的合法直接子元素只有 <code><caption></caption>、<colgroup></colgroup>、<thead>、<code><tbody>、<code><tfoot> 和 <code><tr>。但其中只有 <code><tr> 能独立撑起表格结构——漏写它,整个表格就“塌”了。
<ul>
<li>写成 <code><table><td>A</td></table>:浏览器会自动补全为 <table><tbody><tr><td>A</td></tr></tbody></table>,但补全行为不可控,老版本 IE 可能完全忽略
<thead>、<code><tbody> 等语义标签虽非强制,但一旦使用,它们内部仍必须包裹 <code><tr>,不能直接放 <code><td>
<li>JS 动态插入行时,必须用 <code>appendChild() 或 insertRow() 往 <tbody> 或 <code><table> 下添加 <code><tr>,而非直接 append <code><td>
<h3><code><th> 和 <code><td> 不是可互换的“样式标签”
<p><code><th> 表达的是语义上的“表头”,不是“加粗居中的 <code><td>”。混用会破坏屏幕阅读器导航、影响 SEO、导致 CSS 选择器错位。
<ul><li><code><th> 应只出现在 <code><thead>(列名)或首列 <code><tbody>(行名),默认有 <code>scope="col" 或 scope="row" 语义
<td>,哪怕内容是数字、图标或空字符串;用 <code><th> 填充数据会让辅助技术误读为“这是标题”
<li>合并单元格时:<code><th colspan="2">销售额</th> 合法,<td colspan="2">2024</td> 合法,但 <th rowspan="2">Q1</th>
<td>Jan</td> 这种跨行后下一行未留空会导致列数错乱
<caption></caption> 是标题,不是装饰性 <h3></h3>
<caption></caption> 是 <table> 的唯一语义化标题,对无障碍访问至关重要。放在外面套个 <code><h3></h3> 看着一样,实际效果天差地别。
- 必须是
<table> 的第一个或最后一个子元素;写在中间会被浏览器移到开头 <li>即使 CSS 设为 <code>visibility: hidden,屏幕阅读器仍会朗读,适合做“视觉隐藏但语义保留”的说明 - 不要用
<div> 或 <code><p></p>模拟标题——它们不属于表格结构,无法被aria-labelledby正确关联 - 空表格(如加载中)也要写
<caption>正在加载数据...</caption>,否则辅助技术可能跳过整个表格
真正容易被忽略的不是“要不要写 <thead>”,而是“写了之后是否确保它里面只有 <code><tr>,且每个 <code><tr> 里全是 <code><th>”。结构松动一环,后续所有 JS 操作、CSS 定位、无障碍支持都会开始掉链子。</th>











