HTML周历最佳实现是display: grid,7列对应周一至周日,48行对应30分钟粒度时间轴;日程用grid-row/column精准定位,小屏应切换为单日视图而非缩放。

HTML 本身没有内置的“周历”组件,table 或 grid 是最直接、可控且兼容性最好的实现方式;用 flex 容易错位,用第三方库(如 FullCalendar)反而增加复杂度,除非你 already 需要月视图+事件拖拽等完整日程功能。
用 display: grid 搭建七列一行的周头 + 24/48 行时间轴
核心是把「周一到周日」作为列,把「每小时」或「每半小时」作为行。推荐按 30 分钟粒度切分,共 48 行(00:00–23:30),这样能对齐多数日程系统的时间块。
实操建议:
- 容器设
display: grid,用grid-template-columns: repeat(7, 1fr)均分日期列 - 用
grid-template-rows: 2rem repeat(48, 1rem)—— 首行留高给日期标题,其余每行代表 30 分钟 - 第一行用
grid-column: 1 / -1跨满 7 列显示周一至周日文字,再用:nth-child(n+2)给后续行加边框或背景色增强可读性 - 避免用
auto-fit或minmax()动态列宽,会导致列宽不一致,日程卡片错位
日程卡片怎么精准定位到某天某时段?
靠 grid-row 和 grid-column 手动计算起始位置。比如:周二(第 2 列)上午 9:30–10:45,对应第 2 列、第 19 行(9:30 是第 19 个 30 分钟块)到第 22 行(10:45 是第 22 块末尾)。
立即学习“前端免费学习笔记(深入)”;
关键点:
- 时间转行号公式:
rowStart = Math.floor((hour * 60 + minute) / 30) + 2(+2 因为第 1 行是标题,第 2 行才是 00:00) -
grid-row: 19 / 23表示从第 19 行开始,到第 23 行前结束(即占 19、20、21、22 四行) - 卡片高度不要设固定
height,否则会挤压网格布局;用min-height+padding控制视觉高度即可 - 多个重叠日程需用
z-index+position: relative微调层叠,但更稳妥的是服务端或 JS 合并同时间段日程,转成标签式横向排列
响应式下怎么不让周历挤成一团?
小屏不是“缩放”,而是“切换视图”——手机端用户根本不需要同时看 7 天 × 48 格。直接用媒体查询隐藏周历,换成单日滚动视图更合理。
实操建议:
- 桌面端保持
grid布局,最小宽度设min-width: 768px - 在
@media (max-width: 767px)中,把周历容器display: none,显示一个<select></select>选日期,再渲染当天的垂直时间轴(用flex-direction: column) - 别试图用
scale或vw缩放整个 grid,字体糊、点击热区偏移、时间块高度失真,问题比解决的多 - 如果硬要保留小屏周视图,至少限制列数:用
grid-template-columns: repeat(3, 1fr)只显示当前日及前后两天,并隐藏非当日的空白行
真正难的不是画出格子,而是时间块与真实日程数据的映射精度——分钟级偏差、跨日事件、时区换算、夏令时跳变,这些在纯 HTML/CSS 层无法处理,必须由 JS 提前归一化时间戳后再生成 grid 位置。别让样式逻辑去承担时间逻辑的职责。



















