应将多级分组拆分为多个独立<table>并用<section aria-labelledby>包裹,每个表格配完整<thead>/<tbody>、<caption>及显式scope属性;键值对改用<dl>而非单列表格。

单张 <table> 套多级分组会破坏屏幕阅读器上下文识别
当把“住院费用”“护理机构服务”“终身储备日规则”等逻辑独立的区块硬塞进同一张 <table>,哪怕用了 <th colspan="4">Hospitalization</th> 或 CSS 视觉分隔,屏幕阅读器仍只将其视为普通行——它无法推断后续 5 行数据都属于这个标题。用户逐单元格导航时,听到的是“First 60 days, $1,600”,却不知道这属于哪一类费用。
根本问题在于:<table> 的语义模型只支持单层行列关系,没有“子区域”概念。辅助技术不会主动将视觉上相邻的 <tr> 归属到上方某个 <th> 下,除非你显式建立结构化隶属关系。
- 用
aria-describedby指向分组标题 ID 是常见补救手段,但仅附加一次描述文本,不随焦点移动重复播报,上下文极易丢失 -
headers属性虽能绑定多个表头 ID,但需为每个<td>手动维护 ID 列表,大型表格易出错且不可维护 - 嵌套
<table>不解决本质问题,反而增加 DOM 深度和 AT 解析负担
拆成多个独立 <table> + <section> 是最健壮的方案
把每个业务分组(如 “Hospitalization”)封装为一个完整、自洽的 <table>,并用 <section aria-labelledby="sec-id"> 包裹,是 WCAG 2.2 和主流 AT(NVDA/JAWS)验证过的最佳实践。
这样做的直接效果是:每个 <table> 都有自己完整的 <thead>/<tbody>、<caption> 和 scope 关联,无需额外 ARIA 修补;同时 <section> 自动成为可跳转 landmark,用户按 Ctrl+Alt+R 就能直达目标区块。
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
<section>必须配aria-labelledby指向内部<h2>的 ID,不能只靠 class 或 textContent -
<h2>必须在<section>内部,且层级连续(页面有唯一<h1>,分组用<h2>,子分类才用<h3>) -
<caption>应写具体描述(如Hospitalization cost breakdown),而非泛泛的“费用明细”
<th scope="row"> 和 <th scope="col"> 必须显式声明
即使表格结构简单,漏掉 scope 也会让屏幕阅读器无法判断某列数据归属哪个维度。例如 <th>First 60 days</th> 若无 scope="row",AT 可能误判为列标题,导致后续单元格读作“Medicare pays, All but $1,600”,完全丢失行语义。
真实场景中,错误常出现在动态渲染表格:后端返回扁平数组,前端循环生成 <tr> 时忘记给首列 <th> 加 scope,或误用 scope="col" 在行标题上。
- 行标题(描述数据行内容)用
scope="row" - 列标题(描述数据列含义)用
scope="col" - 避免在
<th>上同时设scope和headers——二者功能重叠且可能冲突 - 响应式表格若隐藏某些列,需同步移除对应
<th>的scope,否则 AT 仍会尝试播报已不可见的上下文
单列键值对别用 <table>,改用 <dl> 或语义化段落
像“保单号: ABC123”“生效日期: 2025-01-01”这类线性键值对,强行套 <table>(哪怕只有一列)会误导 AT 认为这是二维数据,触发不必要的行列导航模式,增加认知负荷。
正确做法是用 <dl>:每个 <dt> 是术语(键),<dd> 是描述(值),天然表达一对一关系;或者用带 aria-label 的 <p> 组合,语义更轻量。
-
<dl>中<dt>和<dd>必须成对出现,不能跳过<dd>留空 - 若后端返回的是对象 { policyNo: "ABC123", effectiveDate: "2025-01-01" },直接映射为
<dl>比转换成二维数组再塞进<table>更直白可靠 - CSS 可通过
dl { display: grid; grid-template-columns: max-content 1fr; }实现与表格相似的对齐效果,不牺牲语义


















