SaaS定价页必须用原生<table>而非div+grid,因其提供唯一正确的二维数据语义;需严格使用<thead><tbody>、scope属性、语义化隐藏列、CSS驱动高亮与数字对齐,确保可访问性、打印、导出及响应式正确。

用 <table> 做 SaaS 定价页,不是“可以”,而是“必须”——只要你的数据是二维对比(功能 × 套餐),就别碰 div + grid 模拟表格。语义错、读屏崩、打印断行、Excel 导出失败,全是绕开原生 <table> 的直接后果。
为什么 pricing 表不能用 div + CSS Grid 布局
常见错误现象:屏幕阅读器读出“盒子、盒子、盒子”,而不是“企业版|API 访问|✓”;Chrome 打印预览中某行被截成两页;用户复制价格粘贴进 Excel,所有内容挤在 A1 单元格里。
根本原因在于,div 没有行列语义,辅助技术无法建立“第 3 列=价格”“第 2 行=专业版”的映射关系。而 SaaS 定价表本质就是结构化二维数据,<table> 是浏览器唯一原生支持该语义的标签。
实操建议:
立即学习“前端免费学习笔记(深入)”;
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
-
<thead>必须只放列标题,每个<th>加scope="col",例如<th scope="col">专业版</th> -
<tbody>每个<tr>对应一个套餐,不嵌套、不省略 - 禁用
colspan/rowspan—— 它们会破坏:nth-child()的列索引连续性,导致移动端样式错位或推荐标识联动失效
移动端隐藏非核心列时,display: none 不等于删 DOM
很多方案在 @media (max-width: 768px) 里对整列 td 和对应 th 写 display: none,结果屏幕阅读器照样读、打印仍出错、SEO 爬虫看到空列。
正确做法是只隐藏视觉,保留语义结构。关键点在于:列头 <th scope="col"> 和数据单元格 <td> 必须共用同一套选择器逻辑。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 给要隐藏的列统一加 class,比如
class="hide-on-mobile" - CSS 写成:
th.hide-on-mobile, td.hide-on-mobile { display: none; } - 不要单独写
th:nth-child(4) { display: none; }—— 这样td没同步隐藏,语义断裂 - 如果必须横向滚动,外层包
<div style="overflow-x: auto">,而非删减列
让“推荐”套餐高亮,纯 CSS 就够,别写 JS 切换
硬塞 class="popular" 再用 JS 控制样式,既增加首屏 JS 体积,又破坏 SSR 可访问性。现代浏览器已支持 :has(),完全可驱动动态标记。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 给推荐列的
<th>加data-popular="true",例如<th scope="col" data-popular="true">企业版</th> - CSS 用:
th[data-popular="true"]::before实现角标,th[data-popular="true"] ~ td:nth-child(3)联动高亮该列所有单元格 - 注意兼容性:Safari 15.4+、Chrome 105+ 支持良好;若需 IE11 或旧 Edge,改用
class="plan-popular"手动维护,但别强求 CSS 驱动
价格数字右对齐和小数点对齐,靠 CSS 不靠空格
写 <td> ¥99.00</td> 是典型反模式:缩放后空格失效、复制进 Excel 多出不可见字符、等宽字体切换后错位。
价格列需要真正“跳出来”,靠的是列级控制,不是给每个单元格打补丁。
实操建议:
立即学习“前端免费学习笔记(深入)”;
- 价格数字单独包裹
<strong>或加class="price-amount",例如<td class="price"><strong>¥299.00</strong>/年</td> - CSS 用
text-align: right+font-variant-numeric: tabular-nums强制等宽数字对齐 - 列样式优先用
td:nth-child(n),但注意序号从整表 DOM 数起(包括<thead>中的<th>) - 避免用
padding-left模拟右对齐——它不解决小数点错位问题
最易被忽略的一点:所有 <th> 必须带 scope 属性,且 <thead> 和 <tbody> 必须显式写出。很多人以为省略它们只是“代码洁癖”,其实这是屏幕阅读器能否正确播报“第 2 列是企业版价格”的分水岭。没写,就等于没做可访问性。

















