
本文介绍一种使用 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 等高级功能的完整日程系统。