必须为表格添加 thead、tbody、caption 和 scope 属性,否则屏幕阅读器无法正确识别表头、结构和语义;table-layout: fixed 的宽度需显式设在 th 上,且需用百分比或 calc() 精确控制各列宽度。

为什么和
不能省略屏幕阅读器靠它们识别表格结构:没 thead,第一行会被当成普通数据读;没 tbody,动态插入的新行可能直接被跳过。Directus 的早期 v-table 就因此在 NVDA 下完全读不出列头。
常见错误现象:
- 用
table tr:first-child 代替 thead 做样式,结果辅助技术无法感知表头范围
- 分页加载时只 append
tr 到 table,没包进 tbody,新行不被朗读
- 服务端渲染漏掉
tbody 标签,前端 JS 补充时 DOM 已解析完毕,语义断裂
caption 和 scope 属性必须显式写
caption 不是装饰,它是表格的“标题”,必须紧贴 table 开头,比如 用户管理列表 。漏掉它,屏幕阅读器就无法说明这张表是干啥的。
th 必须带 scope 属性,否则行列关系对辅助技术不可见:
- 列头用
scope="col"
- 首行列头(如“姓名”“操作”)用
scope="row"
- 排序箭头放在
th::after 里?那 scope 更不能漏——否则“已按姓名升序”状态对视障用户完全透明
别用 div 模拟 table,哪怕加了 ARIA
DOM 解析器不认 ARIA。把 div 设成 display: table,再塞一堆 role="row" 和 aria-colindex,视觉上像,但屏幕阅读器仍把它当普通流式内容处理。
DeepBI DHTML 页面生成器
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力:
- 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面;
- 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”;
- 提及位于 `apps/console/src/featur
下载
真实重构场景中容易踩的坑:
- 框架组件(如 v-table)内部用
div + grid 渲染,但没提供原生 table 的 fallback 结构
- 为兼容旧版 IE 强行降级为 div 布局,结果移动端 VoiceOver 完全无法导航表格
- 用
aria-live 通知数据更新,却没同步更新 th 的 scope 或 rowspan,导致焦点移入后读错上下文
table-layout: fixed 的宽度必须落在 th 上
设了 table { table-layout: fixed; width: 100%; } 还不管用?问题大概率出在宽度没下达到 th。浏览器只认 th:nth-child(1) { width: 15%; } 这种写法,父容器设 width 没用。
关键细节:
- 所有关键列都该用百分比或
calc() 显式声明宽度,比如“操作”列固定 80px,“描述”列用 th:nth-child(3) { width: calc(100% - 240px); }
- 未设宽度的列会被压缩到最小内容宽,长文本会撑破整行
-
white-space: nowrap 和 text-overflow: ellipsis 必须同时加在 th 和 td 上,否则行高不一致,滚动时错位
真正难的不是写对 table-layout: fixed,而是让每一列的宽度值能扛住不同长度的数据——比如“备注”列填满 500 字时,“ID”列仍保持 80px 不膨胀,这要求宽度逻辑必须锚定在 th 上,而不是靠 JS 算完再塞 style。
thead,第一行会被当成普通数据读;没 tbody,动态插入的新行可能直接被跳过。Directus 的早期 v-table 就因此在 NVDA 下完全读不出列头。table tr:first-child 代替 thead 做样式,结果辅助技术无法感知表头范围tr 到 table,没包进 tbody,新行不被朗读tbody 标签,前端 JS 补充时 DOM 已解析完毕,语义断裂caption 不是装饰,它是表格的“标题”,必须紧贴 table 开头,比如 用户管理列表 。漏掉它,屏幕阅读器就无法说明这张表是干啥的。th 必须带 scope 属性,否则行列关系对辅助技术不可见:scope="col"
scope="row"
th::after 里?那 scope 更不能漏——否则“已按姓名升序”状态对视障用户完全透明div 设成 display: table,再塞一堆 role="row" 和 aria-colindex,视觉上像,但屏幕阅读器仍把它当普通流式内容处理。
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
div + grid 渲染,但没提供原生 table 的 fallback 结构aria-live 通知数据更新,却没同步更新 th 的 scope 或 rowspan,导致焦点移入后读错上下文table { table-layout: fixed; width: 100%; } 还不管用?问题大概率出在宽度没下达到 th。浏览器只认 th:nth-child(1) { width: 15%; } 这种写法,父容器设 width 没用。calc() 显式声明宽度,比如“操作”列固定 80px,“描述”列用 th:nth-child(3) { width: calc(100% - 240px); }
white-space: nowrap 和 text-overflow: ellipsis 必须同时加在 th 和 td 上,否则行高不一致,滚动时错位table-layout: fixed,而是让每一列的宽度值能扛住不同长度的数据——比如“备注”列填满 500 字时,“ID”列仍保持 80px 不膨胀,这要求宽度逻辑必须锚定在 th 上,而不是靠 JS 算完再塞 style。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










