
本文介绍一种使用 css grid 构建的响应式会议日程表方案,支持桌面端(时间轴垂直、地点横向排列)与移动端(地点垂直、时间轴横向并可水平滚动)双模式切换,并原生支持跨列/跨行的“休息时段”区块布局。
本文介绍一种使用 css grid 构建的响应式会议日程表方案,支持桌面端(时间轴垂直、地点横向排列)与移动端(地点垂直、时间轴横向并可水平滚动)双模式切换,并原生支持跨列/跨行的“休息时段”区块布局。
在组织多场地、多时段的会议或活动时,一个清晰、灵活且适配多设备的日程可视化方案至关重要。传统基于
或浮动布局的实现难以优雅处理“跨地点休息时段”(如茶歇覆盖全部三个会场),而列表式结构(如
+
- )又缺乏二维空间控制能力。CSS Grid 凭借其显式的行列定义与区域合并能力,成为构建此类动态时间表的理想选择。
以下是一个生产就绪的精简模板,核心逻辑如下:
- 使用 grid-area 精确定义每个区块在网格中的起止行列;
- 通过 @media 查询区分横屏(桌面)与竖屏(移动)布局,避免依赖 orientation(该属性在桌面浏览器中不可靠);
- 移动端启用水平滚动(overflow-x: auto),确保窄屏下完整内容可见;
- 所有区块均采用语义化 ID,并支持无障碍标签(建议后续补充 aria-label 和 role=”region”)。
✅ 完整 HTML + CSS 示例
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"/> <title>会议日程表</title> <style> * { box-sizing: border-box; } body { margin: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; line-height: 1.5; } #timetable { display: grid; width: 100vw; min-height: 100vh; padding: 1rem; gap: 0.75rem; /* 默认为移动端布局:地点在左,时间在上 */ grid-template-rows: repeat(3, 1fr); /* 3 地点行 */ grid-template-columns: 8rem repeat(12, 1fr); /* 第一列为地点,后12列为时间槽(如每30min一格) */ overflow-x: auto; scroll-behavior: smooth; } /* 桌面端:转为时间在左、地点在上 */ @media (min-width: 768px) { #timetable { grid-template-rows: 3rem repeat(12, 1fr); /* 第一行为时间标题,后12行为时间槽 */ grid-template-columns: 6rem repeat(3, 1fr); /* 第一列为时间,后3列为地点 */ overflow-x: visible; } } /* 公共样式 */ .slot { padding: 0.75rem; border-radius: 0.375rem; color: #333; font-weight: 500; white-space: normal; overflow: hidden; text-overflow: ellipsis; display: flex; flex-direction: column; justify-content: center; align-items: flex-start; } .slot-time, .slot-location { background-color: #f1f5f9; font-size: 0.875rem; font-weight: 600; color: #475569; display: flex; align-items: center; justify-content: center; } /* 示例区块 —— 可按需替换为真实数据 */ #location-a { grid-area: 2 / 1 / 3 / 2; background-color: #e0f2fe; } #location-b { grid-area: 3 / 1 / 4 / 2; background-color: #dbeafe; } #location-c { grid-area: 4 / 1 / 5 / 2; background-color: #f0fdf4; } #time-0900 { grid-area: 1 / 2 / 2 / 3; background-color: #f1f5f9; } #time-0930 { grid-area: 1 / 3 / 2 / 4; background-color: #f1f5f9; } #time-1000 { grid-area: 1 / 4 / 2 / 5; background-color: #f1f5f9; } #talk-1 { grid-area: 2 / 2 / 3 / 4; background-color: #bfdbfe; } #talk-2 { grid-area: 3 / 3 / 4 / 5; background-color: #c7d2fe; } #lunch { grid-area: 2 / 4 / 4 / 5; background-color: #fcd34d; } /* 跨2地点 */ #keynote { grid-area: 2 / 5 / 5 / 6; background-color: #a78bfa; } /* 跨3地点 */ /* 桌面端重定位 */ @media (min-width: 768px) { #location-a { grid-area: 1 / 2 / 2 / 3; background-color: #e0f2fe; } #location-b { grid-area: 1 / 3 / 2 / 4; background-color: #dbeafe; } #location-c { grid-area: 1 / 4 / 2 / 5; background-color: #f0fdf4; } #time-0900 { grid-area: 2 / 1 / 3 / 2; background-color: #f1f5f9; } #time-0930 { grid-area: 3 / 1 / 4 / 2; background-color: #f1f5f9; } #time-1000 { grid-area: 4 / 1 / 5 / 2; background-color: #f1f5f9; } #talk-1 { grid-area: 2 / 2 / 3 / 3; background-color: #bfdbfe; } #talk-2 { grid-area: 3 / 3 / 4 / 4; background-color: #c7d2fe; } #lunch { grid-area: 2 / 4 / 4 / 5; background-color: #fcd34d; } /* 跨2时间槽 */ #keynote { grid-area: 2 / 2 / 5 / 5; background-color: #a78bfa; } /* 跨3时间槽 & 3地点 → 实际占满整个区域 */ } </style> </head> <body> <div id="timetable"> <!-- 地点标题(移动端第一列) --> <div id="location-a" class="slot slot-location">主会场 A</div> <div id="location-b" class="slot slot-location">分会场 B</div> <div id="location-c" class="slot slot-location">线上会议室 C</div> <!-- 时间标题(移动端顶部行) --> <div id="time-0900" class="slot slot-time">09:00</div> <div id="time-0930" class="slot slot-time">09:30</div> <div id="time-1000" class="slot slot-time">10:00</div> <div id="time-1030" class="slot slot-time">10:30</div> <div id="time-1100" class="slot slot-time">11:00</div> <!-- 活动区块 --> <div id="talk-1" class="slot">主题演讲:未来趋势</div> <div id="talk-2" class="slot">圆桌讨论:技术实践</div> <div id="lunch" class="slot">午餐 & 交流</div> <div id="keynote" class="slot">重磅主旨演讲</div> </div> </body> </html>
⚠️ 关键注意事项
- 避免 orientation: portrait/landscape 媒体查询:该特性在桌面浏览器中不触发,且平板横竖屏切换时行为不稳定;推荐使用 min-width(如 768px)或 min-height 配合视口单位判断。
- 跨区域合并必须显式声明:Grid 中“跨多列/多行”的区块(如茶歇、主旨演讲)需用 grid-area: r1 / c1 / r2 / c2 明确范围,不能依赖自动流式布局。
- 移动端水平滚动体验优化:
- 添加 scroll-behavior: smooth 提升滑动流畅度;
- 对容器设置 overscroll-behavior-x: contain 可防止滚动穿透到父级;
- 建议为 .slot 添加 flex-shrink: 0 防止内容被压缩。
- 可访问性增强:为每个 .slot 添加 aria-label(如 aria-label=”主会场A,09:00–09:30:主题演讲”),并用
包裹标题区域。
✅ 总结
本方案以 CSS Grid 为核心,摆脱了表格语义束缚与列表布局局限,天然支持二维空间伸缩与区域合并,同时通过媒体查询实现真正的响应式重构——不仅是尺寸适配,更是信息架构的逻辑重组。开发者可基于此模板快速注入真实日程数据(建议配合 JavaScript 动态渲染),并轻松扩展为支持拖拽编辑、实时状态标记、导出 PDF 等高级功能的完整日程系统。