用 写基础表格三步即可:1. 用 定义容器;2. 用 添加行;3. 在每行中用 (表头)或 (数据)添加单元格,确保层级正确、数量一致,并显式声明 以保障样式与脚本可靠性。

用 <table> 写基础表格,三步就能跑起来
<p>直接写 <code><table> 是最轻量、兼容性最强的方式,不需要框架或 JS 就能渲染多行多列数据。关键不是“能不能”,而是“怎么写不翻车”。
<p>常见错误是把 <code><tr> 和 <code><td> 嵌套错层级,或者漏掉 <code><tbody> 导致后续加样式或 JS 操作时出问题。
<ul><li><code><thead> 里只放 <code><tr> + <code><th>,别塞 <code><td>
<li>每行 <code><tr> 的单元格数尽量一致,否则浏览器会自动补空格,但 colspan/rowspan 要手动算清楚
<li>如果数据来自后端 JSON,别手敲 <code><tr> —— 用模板字符串或循环拼接,例如:<code>`<tr>
<td>${item.name}</td>
<td>${item.age}</td>
</tr>`
表头固定、内容滚动?<tbody> 必须显式声明
<p>想让 <code><thead> 固定、<code><tbody> 滚动,CSS 的 <code>display: block + overflow-y: auto 只对 <tbody> 生效——前提是它得是真实存在的标签,不能靠浏览器隐式生成。
<p>省略 <code><tbody> 标签时,DOM 中它依然存在(浏览器自动补),但部分 CSS 选择器或 JS 查询(比如 <code>document.querySelector('tbody'))可能失效,尤其在 SSR 或微前端场景下更不稳定。
- 必须写
<tbody> 开闭标签,哪怕里面暂时没内容
<li>滚动容器高度要设死,比如 <code>max-height: 300px,否则 <tbody> 不会触发滚动条
<li>固定表头需配合 <code>position: sticky 和 top: 0,但 IE 不支持,如需兼容得用 JS 模拟
跨行跨列怎么不出错?先算 rowspan/colspan 再写 HTML
rowspan 和 colspan 看似简单,实际最容易导致表格结构错乱:浏览器不会报错,但渲染结果和预期差一列、少一行,排查极耗时间。
典型错误是把 rowspan="3" 写在第 2 行的单元格上——它只能从当前行开始向下占位,不能“回溯”覆盖上面已渲染的行。
- 跨行单元格必须放在它所覆盖的**最顶行**,且该位置原本没有其他单元格
- 跨列同理:必须放在它覆盖的**最左列**,且左侧不能有未闭合的
<td>
<li>建议画个草图,标出每格的行列坐标(从 0 开始),再填 rowspan/colspan 值,比边写边试快得多</li>
<h3>纯静态表格够用,但数据变多就得考虑替代方案</h3>
<p>当行数超过 200、列数超 15,或者需要排序/筛选/导出,硬写 <code><table> 会明显卡顿——DOM 节点太多,重排重绘压力大,而且没内置交互逻辑。
<p>这时候不是“该不该用 table”,而是“该不该用原生 table”。React/Vue 项目里,<code><table> 仍是语义化首选,但建议用虚拟滚动库(如 <code>react-virtualized)包裹;纯 HTML 页面可引入 datatables.net 这类轻量 JS 插件,它底层还是用 <table>,但做了性能优化和功能封装。
<p>容易被忽略的是语义细节:屏幕阅读器依赖 <code><th scope="col"> 和 <code><caption></caption> 正确识别表结构,这些不是“锦上添花”,而是无障碍合规的硬性要求。
<tbody> 必须显式声明
<p>想让 <code><thead> 固定、<code><tbody> 滚动,CSS 的 <code>display: block + overflow-y: auto 只对 <tbody> 生效——前提是它得是真实存在的标签,不能靠浏览器隐式生成。
<p>省略 <code><tbody> 标签时,DOM 中它依然存在(浏览器自动补),但部分 CSS 选择器或 JS 查询(比如 <code>document.querySelector('tbody'))可能失效,尤其在 SSR 或微前端场景下更不稳定。
- 必须写
<tbody> 开闭标签,哪怕里面暂时没内容 <li>滚动容器高度要设死,比如 <code>max-height: 300px,否则<tbody> 不会触发滚动条 <li>固定表头需配合 <code>position: sticky和top: 0,但 IE 不支持,如需兼容得用 JS 模拟 - 跨行单元格必须放在它所覆盖的**最顶行**,且该位置原本没有其他单元格
- 跨列同理:必须放在它覆盖的**最左列**,且左侧不能有未闭合的
<td> <li>建议画个草图,标出每格的行列坐标(从 0 开始),再填 rowspan/colspan 值,比边写边试快得多</li> <h3>纯静态表格够用,但数据变多就得考虑替代方案</h3> <p>当行数超过 200、列数超 15,或者需要排序/筛选/导出,硬写 <code><table> 会明显卡顿——DOM 节点太多,重排重绘压力大,而且没内置交互逻辑。 <p>这时候不是“该不该用 table”,而是“该不该用原生 table”。React/Vue 项目里,<code><table> 仍是语义化首选,但建议用虚拟滚动库(如 <code>react-virtualized)包裹;纯 HTML 页面可引入datatables.net这类轻量 JS 插件,它底层还是用<table>,但做了性能优化和功能封装。 <p>容易被忽略的是语义细节:屏幕阅读器依赖 <code><th scope="col"> 和 <code><caption></caption>正确识别表结构,这些不是“锦上添花”,而是无障碍合规的硬性要求。
跨行跨列怎么不出错?先算 rowspan/colspan 再写 HTML
rowspan 和 colspan 看似简单,实际最容易导致表格结构错乱:浏览器不会报错,但渲染结果和预期差一列、少一行,排查极耗时间。
典型错误是把 rowspan="3" 写在第 2 行的单元格上——它只能从当前行开始向下占位,不能“回溯”覆盖上面已渲染的行。










