表格必须用<table>包裹,<tr>须置于<thead>或<tbody>内;需用<th>(带scope属性)区分表头与数据;价格应包裹在<span class="price">中;移动端应保留全部DOM结构并用CSS重排而非隐藏。

表格结构必须用 <table> 包裹,<tr> 只能直接放在 <tbody> 或 <thead> 里
浏览器会自动补全缺失的 <tbody>,但手动写出来更可控,尤其当你要用 CSS 选中某类 <tr> 时。比如给价格行加背景色,如果没写 <tbody>,tbody tr.price-row 就失效了。
常见错误是把 <tr> 直接塞进 <table>,结果样式错乱、JS 获取 rows 长度不准,甚至某些旧版 Safari 渲染异常。
- 正确结构:
<table><thead><tr><th>项目</th></tr></thead><tbody><tr class="price-row"><td>基础版</td></tr></tbody></table></li> <li>避免写法:<code><table><tr><td>…</td></tr></table></li> <li>如果只有表头没有数据,也得保留空 <code><tbody></tbody>
,否则document.querySelector('tbody').rows.length会报错
用 <th> 和 <td> 区分表头与数据,别全用 <td>
<th> 默认加粗居中,语义上表示“列名”或“行名”,对屏幕阅读器、SEO 和后续用 JS 按列排序都关键。价格表里,第一列是服务项(<th scope="row">),第一行是套餐名(<th scope="col">),其他全是 <td>。
不加 scope 属性的话,辅助工具无法判断某格数据对应哪行哪列,用户查“企业版年费”容易迷路。
立即学习“前端免费学习笔记(深入)”;
- 行标题写法:
<tr><th scope="row">基础版</th><td>¥99</td><td>¥199</td></tr></li> <li>列标题写法:<code><tr><th></th><th scope="col">月付</th><th scope="col">年付</th></tr></li> <li>千万别用 <code><td>
冒充表头——CSS 加粗顶不了语义,WCAG 也会判为可访问性缺陷
价格数字统一用 <span class="price"> 包裹,方便样式和脚本处理
纯文本价格(如 ¥299)很难单独调色、加单位、做动态更新。一旦要支持多币种或促销价划线,就得改 HTML 结构。提前用 <span> 标出价格区域,后续加 JS 或 CSS 都省事。
注意别嵌套错层级:价格单元格是 <td>,里面再放 <span class="price">,而不是反过来。
- 推荐写法:
<td><span class="price">¥299</span><span class="unit">/年</span></td></li> <li>避免写法:<code><span class="price"><td>¥299</td></span></li> <li>如果价格含折扣(如 ¥499 <del>¥699</del>),<code><del>
要和<span class="price">同级,别塞进里面
移动端窄屏下,<tr> 分类展示要用 CSS 重排,不是删减内容
有人用 @media 直接 display: none 隐藏整行,结果搜索引擎抓不到价格、语音助手读不出年付选项。真正“分类展示”是指按设备能力切换呈现逻辑:桌面端横向对比,手机端纵向堆叠,但所有数据仍保留在 DOM 中。
核心技巧是用 display: contents 或 flex + order 控制视觉顺序,而不是删 HTML。
- 可行方案:给每个
<tr>加 data-type(如data-type="monthly"),用 JS 按需提取并重排,而非靠 CSS 隐藏 - 风险操作:用
visibility: collapse在 table 中行为不稳定,Firefox 和 Chrome 表现不一致 - 最简 fallback:用
overflow-x: auto包住<table>,至少保证数据可滚动查看
表格看似简单,但价格表常要对接支付系统、被爬虫收录、供视障用户朗读——<tr> 不是随便画的横线,它是语义骨架的第一层支撑。漏掉 <thead> 或混用 <th>/<td>,后面加任何交互功能都会卡在这一步。



















