在 Hugo 生态系统中,主题是赋予网站外观和感觉的关键。从零开始创建一个全新的 Hugo 主题,是一个既有挑战性又极具回报的过程。它不仅能让你深入理解 Hugo 的模板系统,还能让你完全掌控网站的设计细节。本指南将带你一步步完成这个过程,从最基础的文件结构到高级的自定义功能。
1. 基础结构与配置文件
每个 Hugo 主题都始于一个特定的目录结构。在你的 Hugo 网站的 themes 目录下创建一个新文件夹,例如 mytheme。在这个文件夹内,你需要创建以下基本子目录:
layouts/: 存放所有的 HTML 模板文件。static/: 存放静态资源,如 CSS、JavaScript、图片等。assets/: 存放需要 Hugo 管道处理的资源,如 Sass、图片优化等。i18n/: 存放国际化语言文件。archetypes/: 存放内容类型的模板。
在主题的根目录下,你需要一个 theme.toml 文件(或者 config.toml/hugo.toml,取决于你的 Hugo 版本和配置偏好),用于定义主题的元数据,如名称、版本、作者等。
name = "mytheme"
baseURL = ""
languageCode = "zh-CN"
theme = "mytheme"
2. 核心布局:_default 目录
Hugo 的布局系统非常强大。通常,你会从 layouts/_default/ 目录开始。这个目录下的模板会被用作网站上所有内容的默认布局。
layouts/_default/baseof.html: 这是主题的“骨架”。它定义了 HTML 文档的基本结构,包括<!DOCTYPE html>,<html>,<head>和<body>标签。<head>部分会包含通用的元数据、CSS 链接和 JavaScript 链接。<body>部分通常会包含一个导航菜单、主要内容区域和页脚。layouts/_default/list.html: 这个模板用于渲染列表页面,例如博客文章列表、分类页面等。它会遍历内容,并以列表的形式显示摘要。layouts/_default/single.html: 这个模板用于渲染单个内容页面,如单篇文章、产品页面等。它会显示内容的全部信息。
在 baseof.html 中,你可以使用 Hugo 的模板函数来插入动态内容。例如:
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Title }} - {{ .Site.Title }}</title>
{{ $styles := resources.Get "css/style.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}">
</head>
<body>
<header>
<h1>{{ .Site.Title }}</h1>
<nav>
<ul>
<li><a href="{{ "/" | relURL }}">首页</a></li>
<li><a href="{{ "/about/" | relURL }}">关于</a></li>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</nav>
</header>
<main>
{{ block "main" . }}
{{ end }}
</main>
<footer>
© {{ now.Year }} {{ .Site.Title }}
</footer>
{{ $scripts := resources.Get "js/script.js" | minify | fingerprint }}
<script src="{{ $scripts.RelPermalink }}"></script>
</body>
</html>
在 single.html 中,你可以继承 baseof.html 并定义 main 块的内容:
{{ define "main" }}
<article>
<h2>{{ .Title }}</h2>
{{ .Content }}
</article>
{{ end }}
3. 页面类型与模板继承
Hugo 允许你为不同类型的内容定义特定的模板。例如,如果你有一个“posts”部分,你可以在 layouts/posts/ 目录下创建 list.html 和 single.html。这些模板会覆盖 layouts/_default/ 下的同名文件。
- 列表模板 (
list.html): 用于显示文章列表。你可以遍历.Pages来获取所有文章,并显示它们的标题、摘要和链接。 - 单页模板 (
single.html): 用于显示单篇文章。你可以访问文章的元数据(如标题、日期、作者)和内容。
4. 导航菜单与侧边栏
Hugo 支持多种方式来创建导航菜单。一种常见的方法是在 config.toml 中定义菜单项,然后在模板中使用 .Site.Menus 变量来渲染它们。
在 config.toml 中:
[menu]
[[menu.main]]
name = "博客"
url = "/blog/"
weight = 1
[[menu.main]]
name = "关于我们"
url = "/about/"
weight = 2
在 layouts/_default/baseof.html 的 <header> 部分,你可以这样渲染菜单:
<nav>
<ul>
{{ range .Site.Menus.main }}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{ end }}
</ul>
</nav>
侧边栏通常也可以通过在 baseof.html 中包含一个特定的模板文件来实现,例如 partials/sidebar.html。
5. 静态资源管理
static/ 目录下的文件会被直接复制到网站的根目录。这意味着如果你将 static/css/style.css 放在那里,它将可以在 yourdomain.com/css/style.css 访问。
assets/ 目录则用于 Hugo 的资产管道。你可以使用 Sass、PostCSS,或者对图片进行优化。Hugo 的 resources 模块提供了强大的功能来处理这些资源。
例如,在 baseof.html 中使用 resources.Get 来处理 CSS:
{{ $styles := resources.Get "css/style.css" | minify | fingerprint }}
<link rel="stylesheet" href="{{ $styles.RelPermalink }}">
这会将 assets/css/style.css 文件编译、压缩并添加一个版本哈希(fingerprint),以确保浏览器始终加载最新版本。
6. 内容类型与 Archetypes
Archetypes 允许你为不同类型的内容创建默认的 frontmatter。在 archetypes/ 目录下创建一个文件(如 default.md, posts.md),Hugo 会在创建新内容时自动填充这些 frontmatter。
例如,archetypes/posts.md:
---
title: ""
date: {{ .Date }}
draft: true
author: ""
tags: []
---
7. 国际化 (i18n)
如果你的网站需要支持多种语言,Hugo 的 i18n 功能至关重要。在 i18n/ 目录下创建语言文件(如 en.toml, zh-CN.toml),然后在模板中使用 i18n 函数来获取翻译后的文本。
例如,i18n/zh-CN.toml:
[home]
other = "首页"
[about]
other = "关于"
在模板中:
<a href="{{ "/" | relURL }}">{{ i18n "home" }}</a>
8. 部署与测试
在开发过程中,使用 hugo server 命令可以在本地启动一个开发服务器。你可以看到实时的更改。一旦主题完成,你可以将其添加到你的 Hugo 网站的 config.toml 中,然后运行 hugo 命令来生成静态文件。
总结
创建 Hugo 主题是一个循序渐进的过程。从理解 Hugo 的模板继承、布局系统,到管理静态资源和内容类型,每一步都至关重要。通过不断实践和探索,你将能够构建出既美观又功能强大的 Hugo 主题,为你的网站带来独特的风格。