th 和 td 看起来都只是 HTML 表格中的单元格,但它们的本质分工完全不同,核心区别就在于语义定义和结构职责:th 用于表头单元格,td 用于数据单元格。如果标签使用错误,影响绝不只是“页面显示差不多”这么简单——屏幕阅读器可能会错误朗读内容,Excel 导出时表头信息可能丢失,自动化测试也更容易出现定位失败;更关键的是,这种语义层面的缺失,单纯依靠 CSS 样式根本无法弥补。

真正的区别不在显示样式,而在 HTML 语义和表格结构作用——th 是表头标签,td 是数据标签;一旦用错,屏幕阅读器无法准确识别、Excel 导出容易丢失标题、自动化测试也可能定位失败。
为什么不能只用 CSS 把 td 伪装成“表头样式”
很多人在写 HTML 表格时会这样处理:。表面上看,这样的显示效果确实像表头,视觉上也没有明显问题,但放到真实项目和生产环境中,其实会埋下三个常见隐患:姓名
- 屏幕阅读器不会把它识别为标题单元格,读取对应数据时通常只会报“张三”,而不会读成“姓名:张三”
- 导出为 Excel 表格时,这类
td往往不会被正确识别为列标题,首行可能直接被当成普通数据行 - 前端自动化测试脚本(如 Cypress 或 Playwright)使用
th定位表头更稳定,而依赖样式匹配td很容易误判、漏选或维护困难
th 必须放在 tr 中,不能直接写进 table
在 JavaScript 动态拼接表格结构时,很多人容易漏掉外层的 tr,例如这样写:
| 姓名 | 年龄 |
|---|
虽然浏览器通常会自动补全 tr,但控制台可能出现 td outside tr 之类的警告,导致 DOM 结构异常,scope 属性失效,thead 的语义逻辑也会受到影响。正确的 HTML 表格写法必须是:
| 姓名 | 年龄 |
|---|
colspan 和 rowspan 在 th 与 td 中语法一致,但语义不能混着用
这两个表格属性本身并不限制只能用于哪一种标签,但具体用在什么位置、承担什么含义,决定了整个 HTML 表格是否容易理解和维护:
是合理的:一个表头横跨两列,下面对应“电话”和“邮箱”联系方式 则不合理:把人名作为标题纵向跨三行并不符合语义,正确写法应为张三 张三 colspan/rowspan的值必须是正整数;如果写成0或负数,浏览器通常会静默忽略,不报错但也不会生效
复杂 HTML 表格中,scope 和 headers 不是可有可无
如果只是单层表头,浏览器和辅助工具靠位置关系推断还能勉强工作;但一旦遇到“部门 → 研发/测试”这样的多级列头,或者“2024年 → Q1/Q2”这种时间维度表头,仅靠嵌套结构往往并不可靠:
- 首行
th如果没有scope="col",屏幕阅读器可能无法把它正确关联到下方整列的td - 跨行或多级表头建议搭配
id+headers使用,例如对应Q1 120 scope="rowgroup"需要结合tbody一起使用,并不是随意加在某个th上就一定有效
最容易被忽视的一点是:即使你通过 CSS 把 th 改成细体、左对齐,它作为表头的语义和可访问性能力依然保留;反过来说,用 td 去冒充 th,无论样式做得多像,也无法补回 HTML 结构本该具备的语义契约。
