grid-template-columns: repeat(7, 1fr) 是日历布局起点,它固定7列结构;但需配合 grid-auto-flow: row 和 grid-auto-rows: minmax(min-content, 1fr) 防塌陷,并用 grid-column-start 动态跳过首日前列,确保语义正确、响应式不破列。

为什么 grid-template-columns: repeat(7, 1fr) 是起点,但不够
直接写 grid-template-columns: repeat(7, 1fr) 确实能撑出 7 列,但 Grid 默认按行填充(row-wise),而日历需要「先填满第一周,再下一行」——这看似符合,实际会出问题:当日期数组长度不是 7 的倍数时,最后一行会缺项,grid-auto-flow 默认不补空格,视觉上就错位了。
真正关键的是让容器「知道它要容纳 7 列」,同时允许子元素自动流入,且不因数量不足而塌陷。此时必须配合 grid-auto-flow: row(显式声明,避免浏览器默认差异)和 grid-auto-rows: minmax(min-content, 1fr)(防高度塌缩)。
-
grid-template-columns固定 7 列,不可省略;否则 Grid 会按内容重算列数 - 不要用
grid-template-rows预设行数——日历行数动态(4–6 行),得靠grid-auto-rows - 若子元素没设置
grid-column或grid-row,它们严格按 DOM 顺序从左到右、从上到下填入
如何用 grid-column-start 跳过首日之前的空格
日历第一行往往不是从周日/周一填起,比如某月 1 号是周三,前面就得空出 3 个格子。不能靠 JS 插入空 <div> 元素(破坏语义、增加维护成本),更稳妥的方式是让第一个日期元素「跳过前 N 列」。<p>假设一周从周一开始(<code>firstDay = 1),当前月 1 号是星期三(dayIndex = 3),那么需空出 3 - 1 = 2 个位置,即第一个日期应从第 3 列开始(列索引从 1 起):
/* CSS */
.calendar-day:first-child {
grid-column-start: 3;
}
- 计算公式:
grid-column-start = (date.getDay() - firstDay + 7) % 7 + 1(getDay()周日=0,需对齐) - 注意:如果
firstDay = 0(周日为始),公式简化为date.getDay() + 1 - 这个样式必须作用在第一个真实日期元素上,且不能被其他
grid-column规则覆盖
响应式断点下保持 7 列,但单格宽度需收缩而非换行
很多人加 @media 后误用 grid-template-columns: repeat(auto-fit, minmax(...))),结果在小屏变成 3 列或 5 列——这不是日历,是卡片流。日历的列数必须恒为 7,否则表头和逻辑全乱。
正确做法是固定列数,只调单元格尺寸:
- 用
grid-template-columns: repeat(7, 1fr)保持结构,不改列数 - 缩小
font-size和内边距,或用minmax(40px, 1fr)设最小宽度(防止挤压过甚) - 禁用
grid-auto-flow: column—— 它会让元素竖向填满,彻底破坏日历阅读流 - 若文字折行影响高度,给单元格加
line-height: 1.2和overflow: hidden防撑高
IE11 兼容性陷阱:不要依赖 grid-auto-flow: row dense
IE11 对 Grid 支持极有限,仅认 display: -ms-grid,且不支持 grid-auto-flow。如果你仍需兼容 IE11,别试图用现代 Grid 模拟日历——直接切回 display: table 或 Flex + 计算 margin。
即使只支持 Edge 16+,也要注意:grid-auto-flow: row dense 在某些旧版 Chromium 中会导致日期错位(dense 会提前填空洞,打乱时间顺序)。生产环境一律用 row,靠 CSS 或 JS 控制起始位置即可。
最易被忽略的一点:Grid 容器若设了 overflow: hidden,而某天内容超长(如带 tooltip 的长文本),可能把下拉框裁掉——日历格子最好设 overflow: visible 或用 position: relative 配合 z-index 处理浮层。











