如何给 Hugo 博客添加优雅的垂直时间线组件

最近有朋友问我栏目的时间线功能是怎么实现的。为了能够在文章中优雅地展示经历或版本更新记录,我使用 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

    博客正在进行代码重构优化。

这样,一个清晰明了且代码优雅的时间线就完成啦。

加载中...
📊 加载中...
感谢Jimmy | 隐私政策 | 赞赏支持
Liu 的 AI 助手