<table>不能作为甘特图骨架,因其本质是二维数据容器而非时间坐标系统,会导致时间对齐错乱、列宽失控、跨时段渲染崩盘,且语义错位;CSS Grid通过列序号锚定日期、动态计算grid-column、配合@supports降级兼容IE11,才是轻量可靠的原生解法。

纯用 <table> 实现可用甘特图,基本不可行——它会立刻在时间对齐、列宽控制、跨时段渲染上崩盘,不是“能画出来”,而是“改一行就全乱”。
为什么 <table> 不能当甘特图骨架
表格本质是二维数据容器,不是时间坐标系统。你硬把日期塞进列头,马上撞上三个硬伤:
- 列宽随任务名长度撑开,时间槽宽度不一致,条形图左右错位
- 任务跨多天时,
colspan需按真实天数算,但“2026-07-10 到 2026-07-15”是 6 天还是 5.99 天?浏览器不帮你四舍五入 - 换粒度(比如从“日”切到“周”)就得重写整个
<thead>和所有colspan值,没法动态响应
更隐蔽的问题是语义错位:<th>7月10日</th> 是时间点,不是表头文本;表格无法表达“这个单元格代表 24 小时区间”,只能当字符串渲染。
grid-column 比 colspan 更靠谱的底层逻辑
CSS Grid 才是 HTML 里最接近时间轴建模的原生能力。关键不是“画格子”,而是用列序号锚定日期:
立即学习“前端免费学习笔记(深入)”;
- 用
grid-template-columns: repeat(30, minmax(120px, 1fr))定义 30 天槽,每列宽度自适应但有底线 - 每个任务条用
grid-column: 5 / 12表示从第 5 列开始、到第 12 列前结束(共占 7 列) - 列号必须由 JS 算出:先统一用
new Date('2026-07-10').getTime()转毫秒,再按起始基准日偏移量换算列索引 - 别在 HTML 里写死
style="grid-column: 5"—— 动态数据必须走 JS 注入 class 或 style
这样换粒度时,只需改列数(repeat(4, 1fr) 表示 4 周)和列宽策略,任务条位置自动重映射,不用动 DOM 结构。
IE11 兼容不是重写,而是降级布局
IE11 不支持 display: grid,但没必要砍掉整个时间轴。用 @supports (display: grid) 包一层即可:
/* 主布局:Grid */
.gantt-container { display: grid; }
@supports not (display: grid) {
/* 降级:Flex 单行滚动 */
.gantt-container { display: flex; overflow-x: auto; }
.gantt-row { flex-shrink: 0; }
}降级后失去列对齐精度,但至少能横向滚动查看全部时间范围,结构语义不变,JS 数据层完全复用。
真正卡住甘特图落地的,从来不是“怎么画一条横线”,而是“怎么让这条线始终对应真实时间刻度”。表格做不到这点,Grid 提供了最轻量的解法,而库(如 frappe-gantt)只是把这套映射逻辑封装得更稳。



















