scope="rowgroup" 仅在 、 或 内部的 上有效,且必须配合 rowspan 显式指定跨行数,绑定其所在行组内的数据行,不可复用、不可混用 scope="row",老旧读屏工具兼容性差,关键场景需用 headers/id 回退。

scope="rowgroup" 必须配合 或 使用
单独写 <th scope="rowgroup"> 没用,浏览器和屏幕阅读器会忽略它。这个值只在 <code><tbody>、<code><thead> 或 <code><tfoot> 内部的 <code>th 上才生效,且该 th 必须是该行组的第一行第一列(或通过 rowspan 覆盖整组起始位置)。
常见错误是把 scope="rowgroup" 放在普通 <tr> 里,或者放在 <code><thead> 里却想让它管 <code><tbody> 的数据——它只能管自己所在的那个行组容器内部的数据行。
<ul>
<li>
<code>scope="rowgroup" 不是“视觉分组标签”,它绑定的是 HTML 结构层级,不是 CSS class 或 div 块
如果用了 <tbody class="sales-q1">,那么它的首行 <code><th scope="rowgroup">Q1 销售数据</th> 才真正管住后面所有 <td>
<li>多个 <code><tbody> 就需要多个 <code>scope="rowgroup" 表头,不能复用一个
rowspan 是 scope="rowgroup" 生效的前提条件之一
单纯写 <th scope="rowgroup">部门</th> 不会自动覆盖下面三行;必须显式用 rowspan 告诉浏览器“这个表头横跨几行”,否则屏幕阅读器不知道它管多高。
例如:一个 <tbody> 包含 4 行数据,你想用首行第一个 <code>th 作为整个组标题,就得写 <th scope="rowgroup" rowspan="4">技术部</th> —— 这样辅助技术才明白“技术部”统领接下来全部 4 行。
-
rowspan 值必须准确匹配该行组内实际数据行数(不含其他 th 行)
- 如果动态渲染时行数不确定,不能硬写死
rowspan="5",得用 JS 计算后注入,否则语义断裂
- 不要用
rowspan="0" 或负数,HTML 规范不支持,多数读屏工具直接跳过
scope="rowgroup" 和 scope="row" 别混用在同一行
同一行里既有 scope="rowgroup" 又有 scope="row" 的 th,会导致屏幕阅读器混淆归属关系。比如:
<tr>
<th scope="rowgroup" rowspan="3">研发组</th>
<th scope="row">张三</th>
</tr>
这里 scope="row" 本意是说明“张三”这一行的后续 td 含义,但因为前面有个跨行的 rowgroup,部分旧版 JAWS 会把“张三”也当作“研发组”的子项,而非独立行标题。
- 要么全用
scope="rowgroup" + rowspan 管整组
- 要么放弃
rowgroup,改用每行一个 scope="row" 表头
- 混合使用只在极少数嵌套很深的报表中出现,且需配合
headers/id 显式绑定兜底
老旧读屏工具对 scope="rowgroup" 兼容性有限
不是所有辅助技术都完整支持 scope="rowgroup"。JAWS 2022 之前版本、NVDA 2021.1 以下,遇到这个值可能直接静音或报错,退回到靠 colspan + 视觉样式猜测结构。
- 关键业务表格(如政府/医疗报表)建议同时加
headers 属性做 fallback,例如:<th id="grp1">研发组</th> + <td headers="grp1">...
<li>测试时务必用真实读屏工具(不止 Chrome 自带朗读)验证,模拟盲人用户听到的播报顺序</li>
<li>如果团队没资源测多版本读屏,优先用 <code>scope="row" + 每行标头,虽然冗余但兼容性稳得多
真正难的不是写对 scope="rowgroup",而是判断什么时候非得用它——多数两层分组用 <tbody> 加 <code>scope="row" 就够了;只有当“组标题”本身不参与数据行列对齐(比如跨多行又不占列位),才值得引入这个语义。
<th scope="rowgroup"> 没用,浏览器和屏幕阅读器会忽略它。这个值只在 <code><tbody>、<code><thead> 或 <code><tfoot> 内部的 <code>th 上才生效,且该 th 必须是该行组的第一行第一列(或通过 rowspan 覆盖整组起始位置)。
scope="rowgroup" 放在普通 <tr> 里,或者放在 <code><thead> 里却想让它管 <code><tbody> 的数据——它只能管自己所在的那个行组容器内部的数据行。
<ul>
<li>
<code>scope="rowgroup" 不是“视觉分组标签”,它绑定的是 HTML 结构层级,不是 CSS class 或 div 块
<tbody class="sales-q1">,那么它的首行 <code><th scope="rowgroup">Q1 销售数据</th> 才真正管住后面所有 <td>
<li>多个 <code><tbody> 就需要多个 <code>scope="rowgroup" 表头,不能复用一个
rowspan 是 scope="rowgroup" 生效的前提条件之一
单纯写 <th scope="rowgroup">部门</th> 不会自动覆盖下面三行;必须显式用 rowspan 告诉浏览器“这个表头横跨几行”,否则屏幕阅读器不知道它管多高。
例如:一个 <tbody> 包含 4 行数据,你想用首行第一个 <code>th 作为整个组标题,就得写 <th scope="rowgroup" rowspan="4">技术部</th> —— 这样辅助技术才明白“技术部”统领接下来全部 4 行。
-
rowspan值必须准确匹配该行组内实际数据行数(不含其他th行) - 如果动态渲染时行数不确定,不能硬写死
rowspan="5",得用 JS 计算后注入,否则语义断裂 - 不要用
rowspan="0"或负数,HTML 规范不支持,多数读屏工具直接跳过
scope="rowgroup" 和 scope="row" 别混用在同一行
同一行里既有 scope="rowgroup" 又有 scope="row" 的 th,会导致屏幕阅读器混淆归属关系。比如:
<tr> <th scope="rowgroup" rowspan="3">研发组</th> <th scope="row">张三</th> </tr>
这里 scope="row" 本意是说明“张三”这一行的后续 td 含义,但因为前面有个跨行的 rowgroup,部分旧版 JAWS 会把“张三”也当作“研发组”的子项,而非独立行标题。
- 要么全用
scope="rowgroup"+rowspan管整组 - 要么放弃
rowgroup,改用每行一个scope="row"表头 - 混合使用只在极少数嵌套很深的报表中出现,且需配合
headers/id显式绑定兜底
老旧读屏工具对 scope="rowgroup" 兼容性有限
不是所有辅助技术都完整支持 scope="rowgroup"。JAWS 2022 之前版本、NVDA 2021.1 以下,遇到这个值可能直接静音或报错,退回到靠 colspan + 视觉样式猜测结构。
- 关键业务表格(如政府/医疗报表)建议同时加
headers属性做 fallback,例如:<th id="grp1">研发组</th>+<td headers="grp1">... <li>测试时务必用真实读屏工具(不止 Chrome 自带朗读)验证,模拟盲人用户听到的播报顺序</li> <li>如果团队没资源测多版本读屏,优先用 <code>scope="row"+ 每行标头,虽然冗余但兼容性稳得多
真正难的不是写对
scope="rowgroup",而是判断什么时候非得用它——多数两层分组用 <tbody> 加 <code>scope="row" 就够了;只有当“组标题”本身不参与数据行列对齐(比如跨多行又不占列位),才值得引入这个语义。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











