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

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



















