用<table>渲染日历需动态计算当月1号星期几并补足前导空单元格,严格分离<thead>与<tbody>,为日期添加语义化class(如other-month、today、in-month),移动端应改用Flex布局而非硬撑表格。

用 <table> 渲染日历需要先算好起始星期和天数
直接硬写 42 个 <td> 是最常见错误——日历每周 7 天,但每月天数不固定(28–31),且第一天未必是周日。必须动态计算当月 1 号是星期几,再补上前导空格单元格。
关键步骤:
- 用
new Date(year, month, 1)获取当月 1 日的getDay()值(0=周日,1=周一…) - 前导空格数 =
firstDayIndex(若按周日为起点)或(firstDayIndex + 6) % 7(若想周一为起点) - 总单元格数固定为 42(6 行 × 7 列),不足则用空
<td></td>填充
表格结构要严格遵循语义:用 <thead> 放星期头,<tbody> 放日期
很多人把星期栏塞进 <tr> 里就完事,结果导致可访问性差、样式难控制。正确结构必须分离表头与内容:
<table>
<thead>
<tr>
<th>日</th><th>一</th><th>二</th><th>三</th><th>四</th><th>五</th><th>六</th>
</tr>
</thead>
<tbody>
<tr><td></td><td></td><td>1</td><td>2</td><td>3</td><td>4</td><td>5</td></tr>
<!-- 后续行... -->
</tbody>
</table>注意:<th> 用于星期头,<td> 用于日期;<thead> 和 <tbody> 不可省略,否则 CSS 的 tbody tr:nth-child(even) 等选择器会失效。
立即学习“前端免费学习笔记(深入)”;
当前日期高亮和禁用非本月日期要用 class 区分,别靠内容判断
渲染时容易把“非本月日期”(前后补白)和“本月日期”混在同一个 <td> 里,仅靠文本内容(如空字符串 vs 数字)做样式区分——这不可靠,且 JS 后续操作困难。
正确做法是给每个 <td> 加明确 class:
-
class="other-month":前/后月份的占位日期(如上月 30、31 或下月 1、2) -
class="today":当天日期(需对比new Date()) -
class="in-month":本月有效日期(默认状态)
这样 CSS 可直接写 td.other-month { color: #ccc; },JS 也能用 document.querySelector('td.today') 精准定位。
响应式日历在小屏上会挤变形,<table> 本身不支持列折叠
<table> 是刚性布局,7 列在手机上必然横向滚动或文字换行。没有 magic fix,只能接受限制或换方案。
如果必须用 table 且要适配移动端:
- 用
table-layout: fixed+ 指定<th>宽度,防止自动撑开 - 加
@media规则把字体缩小、内边距减半,但效果有限 - 真正可靠的方案是:小屏改用
<div>+ Flex 布局重绘,而非强撑<table>
别指望 <table> 自动变成竖排日历——它不是为这个设计的,强行 hack 会增加维护成本。



















