最近有朋友问我栏目的时间线功能是怎么实现的。为了能够在文章中优雅地展示经历或版本更新记录,我使用 Hugo 的 Shortcode 功能配合 CSS 实现了一个垂直时间线组件。本文将简要介绍其实现原理,并分享完整代码。
实现思路
实现这个功能的核心思想是利用 Hugo 的 Shortcode 来生成 HTML 结构,并通过 CSS 处理布局和连线。
为了保持代码的语义化(Semantic HTML),我们将时间线视为一个无序列表(<ul>),每一个时间节点则是列表项(<li>)。这比单纯使用 <div> 堆砌更符合 Web 标准,对 SEO 和辅助阅读设备也更友好。
代码实现
我们需要创建两个 Shortcode 文件:容器和列表项。
容器组件 (timeline)
创建文件 layouts/shortcodes/timeline.html:
<ul class="timeline-container">
{{ .Inner }}
</ul>
子项组件 (timeline-item)
创建文件 layouts/shortcodes/timeline-item.html:
<li class="timeline-item">
<div class="timeline-marker"></div>
<div class="timeline-content">
<p class="timeline-date">{{ .Get "date" }}</p>
<div class="timeline-text">{{ .Inner }}</div>
</div>
</li>
样式定义 (CSS)
以下是完整的 CSS 样式代码(支持响应式和深色模式)。你可以将其添加到你的 SCSS 或 CSS 文件中(例如 assets/scss/custom.scss):
/* 时间线样式 */
.timeline-container {
max-width: 600px;
margin: 40px auto;
padding: 0 20px;
position: relative;
background: transparent;
list-style: none;
}
.timeline-container::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 50%;
width: 2px;
background: var(--timeline-line, #e6e6e6);
transform: translateX(-50%);
transition: background 0.3s;
}
.timeline-item {
display: flex;
margin-bottom: 40px;
position: relative;
}
.timeline-marker {
width: 16px;
height: 16px;
border-radius: 50%;
background: linear-gradient(135deg, var(--primary-color, #4285f4), var(--primary-color-dark, #1a237e));
border: 3px solid var(--timeline-bg, #fff);
position: absolute;
left: 50%;
transform: translateX(-50%);
z-index: 1;
box-shadow: 0 0 0 4px var(--timeline-shadow, #e3f2fd);
transition: background 0.3s, box-shadow 0.3s;
}
.timeline-content {
width: calc(50% - 40px);
padding: 0px 10px 12px 15px;
border-radius: 10px;
background: var(--timeline-bg, #fff);
box-shadow: 0 3px 16px rgba(0, 0, 0, 0.10);
color: var(--timeline-text, #263238);
transition: background 0.3s, color 0.3s, box-shadow 0.3s;
margin-top: 0;
}
.timeline-item:nth-child(odd) .timeline-content {
margin-left: auto;
}
.timeline-item:nth-child(even) .timeline-content {
margin-right: auto;
}
.timeline-date {
color: var(--primary-color, #4285f4);
margin-bottom: 10px;
font-weight: bold;
}
.timeline-text {
line-height: 1.6;
}
/* 响应式设计 - 时间线在小屏幕上改为单列布局 */
@media (max-width: 768px) {
.timeline-container {
max-width: 100%;
}
.timeline-container::before {
left: 20px;
}
.timeline-item {
flex-direction: column;
}
.timeline-marker {
left: 20px;
}
.timeline-content {
width: calc(100% - 45px);
margin-left: 45px !important;
}
}
/* 时间线深色模式 */
[data-scheme="dark"] {
--timeline-bg: #23272e;
--timeline-line: #31343a;
--timeline-text: #e6e6e6;
--timeline-shadow: #181a20;
--primary-color: #64b5f6;
--primary-color-dark: #1976d2;
}
[data-scheme="dark"] .timeline-content {
background: linear-gradient(135deg, #23272e 80%, #262a32 100%);
color: var(--timeline-text, #e6e6e6);
box-shadow: 0 3px 16px rgba(0, 0, 0, 0.40);
border: 1px solid #31343a;
}
[data-scheme="dark"] .timeline-marker {
background: linear-gradient(135deg, #64b5f6, #1976d2);
border: 3px solid #23272e;
box-shadow: 0 0 0 4px #181a20;
}
[data-scheme="dark"] .timeline-date {
color: #90caf9;
}
使用方法
定义好组件后,在 Markdown 文件中就能非常方便地调用了。
{{< timeline >}}
{{< timeline-item date="2025-12" >}}
发布了这篇关于时间线实现的教程。
{{< /timeline-item >}}
{{< timeline-item date="2024-01" >}}
博客正在进行代码重构优化。
{{< /timeline-item >}}
{{< /timeline >}}
以下是上述代码渲染后的实际效果:
-
2025-12
发布了这篇关于时间线实现的教程。 -
2024-01
博客正在进行代码重构优化。
这样,一个清晰明了且代码优雅的时间线就完成啦。