创建新主题
本篇教程将深入探讨如何在Hugo中创建全新的网站主题。我们将从基础概念入手,逐步讲解主题的结构、关键文件以及如何自定义内容布局和样式。无论您是Hugo新手还是经验丰富的开发者,本教程都将为您提供宝贵的指导,帮助您构建出符合您特定需求的个性化主题。
主题结构与核心组件
Hugo的主题遵循一套标准化的目录结构,这使得组织和管理主题文件变得直观高效。理解这一结构是创建新主题的第一步。
1. layouts/ 目录:
这是主题的核心,存放着所有用于渲染网站内容的模板文件。Hugo使用Go模板语言,并支持层叠覆盖机制。
layouts/_default/: 包含默认的列表和单页模板。当特定类型的内容没有自定义布局时,Hugo会回退到这些文件。list.html: 用于渲染列表页(如博客文章列表、分类页面)。single.html: 用于渲染单个内容页面(如文章详情页)。
layouts/index.html: 网站首页的模板。layouts/partials/: 存放可重用的模板片段,例如页眉、页脚、导航栏等。这些片段可以通过{{ partial "name.html" . }}调用。layouts/section/: 针对特定内容类型(section)的布局,例如layouts/posts/list.html会被用于/posts/目录下的列表页。layouts/taxonomy/: 用于分类(taxonomy)列表和单页的模板,例如layouts/categories/list.html。
2. static/ 目录:
所有静态文件,如CSS、JavaScript、图片、字体等,都应放在此处。Hugo会将此目录下的内容直接复制到网站的根目录。
3. assets/ 目录:
用于Hugo Pipes,特别是处理图片和CSS/JS。如果您需要进行图片处理(如裁剪、缩放)或使用Sass/SCSS,通常会在此目录下组织源文件。
4. i18n/ 目录:
存放多语言翻译文件,使用YAML格式。
5. archetypes/ 目录:
用于定义新内容文件(如文章、页面)的默认元数据(frontmatter)结构。例如,archetypes/default.md 定义了所有新内容的默认frontmatter。
创建第一个主题
要创建一个新主题,您可以在Hugo项目的根目录下运行以下命令:
hugo new theme mytheme
这将在您的项目根目录下创建一个名为 mytheme 的新目录,并填充一个基本的主题结构。
配置主题
创建主题后,您需要告诉Hugo使用您的新主题。编辑项目根目录下的 config.toml 文件(或 config.yaml, config.json),添加或修改 theme 参数:
baseURL = "http://example.org/"
languageCode = "zh-CN"
title = "我的新网站"
theme = "mytheme"
基础布局实现
让我们从最基本的布局开始。
layouts/_default/baseof.html (基础模板):
这是所有其他模板继承的“骨架”。
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Site.Title }}</title>
{{- with .Site.Params.description -}}
<meta name="description" content="{{ . }}">
{{- end -}}
{{- with .Site.Params.keywords -}}
<meta name="keywords" content="{{ delimit . ", " }}">
{{- end -}}
{{- if .Site.Params.author -}}
<meta name="author" content="{{ .Site.Params.author }}">
{{- end -}}
<link rel="stylesheet" href="{{ "css/style.css" | relURL }}">
</head>
<body>
<header>
<h1><a href="{{ "/" | relURL }}">{{ .Site.Title }}</a></h1>
<nav>
<ul>
{{- range .Site.Menus.main -}}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{- end -}}
</ul>
</nav>
</header>
<main>
{{ block "main" . }}
{{ end }}
</main>
<footer>
<p>© {{ now.Year }} {{ .Site.Title }}</p>
</footer>
{{- block "scripts" . }}
{{- end }}
</body>
</html>
layouts/_default/single.html (单页模板):
它将继承 baseof.html 并填充 main 块。
{{ define "main" }}
<article>
<h2>{{ .Title }}</h2>
{{ .Content }}
</article>
{{ end }}
layouts/_default/list.html (列表模板):
用于渲染文章列表。
{{ define "main" }}
<article>
<h2>{{ .Title }}</h2>
<ul>
{{- range .Pages -}}
<li>
<h3><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
<p>{{ .Summary }}...</p>
</li>
{{- end -}}
</ul>
</article>
{{ end }}
添加静态资源 (CSS)
创建一个 static/css/style.css 文件:
body {
font-family: sans-serif;
line-height: 1.6;
margin: 20px;
}
header {
border-bottom: 1px solid #eee;
padding-bottom: 10px;
margin-bottom: 20px;
}
nav ul {
list-style: none;
padding: 0;
}
nav ul li {
display: inline-block;
margin-right: 15px;
}
article {
margin-bottom: 30px;
}
footer {
margin-top: 30px;
padding-top: 10px;
border-top: 1px solid #eee;
font-size: 0.9em;
color: #777;
}
使用部分模板 (Partials)
创建 layouts/partials/header.html 和 layouts/partials/footer.html。
layouts/partials/header.html:
<header>
<h1><a href="{{ "/" | relURL }}">{{ .Site.Title }}</a></h1>
<nav>
<ul>
{{- range .Site.Menus.main -}}
<li><a href="{{ .URL }}">{{ .Name }}</a></li>
{{- end -}}
</ul>
</nav>
</header>
layouts/partials/footer.html:
<footer>
<p>© {{ now.Year }} {{ .Site.Title }}</p>
</footer>
然后,在 layouts/_default/baseof.html 中调用它们:
<!DOCTYPE html>
<html lang="{{ .Site.LanguageCode }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ .Site.Title }}</title>
{{- with .Site.Params.description -}}
<meta name="description" content="{{ . }}">
{{- end -}}
{{- with .Site.Params.keywords -}}
<meta name="keywords" content="{{ delimit . ", " }}">
{{- end -}}
{{- if .Site.Params.author -}}
<meta name="author" content="{{ .Site.Params.author }}">
{{- end -}}
<link rel="stylesheet" href="{{ "css/style.css" | relURL }}">
</head>
<body>
{{ partial "header.html" . }}
<main>
{{ block "main" . }}
{{ end }}
</main>
{{ partial "footer.html" . }}
</body>
</html>
定义菜单
您可以在 config.toml 中定义菜单项。
baseURL = "http://example.org/"
languageCode = "zh-CN"
title = "我的新网站"
theme = "mytheme"
[params]
description = "一个关于足球世界杯的网站。"
keywords = ["世界杯", "足球", "赛事"]
author = "世界杯官方"
[[menu.main]]
name = "首页"
url = "/"
weight = 1
[[menu.main]]
name = "关于我们"
url = "/about/"
weight = 2
[[menu.main]]
name = "联系方式"
url = "/contact/"
weight = 3
支持不同内容类型
Hugo 允许您为不同的内容类型(如文章、页面)定义特定的布局。
例如,如果您想为文章(默认在 content/posts/ 下)创建自定义列表和单页布局:
- 在
layouts/目录下创建posts/目录。 - 创建
layouts/posts/list.html和layouts/posts/single.html。
layouts/posts/single.html:
{{ define "main" }}
<article>
<h2>{{ .Title }}</h2>
{{ with .Params.author }}<p>作者: {{ . }}</p>{{ end }}
{{ with .Params.date }}<p>日期: {{ .Format "2006-01-02" }}</p>{{ end }}
{{ .Content }}
</article>
{{ end }}
layouts/posts/list.html:
{{ define "main" }}
<article>
<h2>{{ .Title }}</h2>
<ul>
{{- range .Pages -}}
<li>
<h3><a href="{{ .RelPermalink }}">{{ .Title }}</a></h3>
{{ with .Params.author }}<p>作者: {{ . }}</p>{{ end }}
{{ with .Params.date }}<p>日期: {{ .Format "2006-01-02" }}</p>{{ end }}
<p>{{ .Summary }}...</p>
</li>
{{- end -}}
</ul>
</article>
{{ end }}
使用 Archetypes
Archetypes 允许您在创建新内容时预设 frontmatter。
在 archetypes/ 目录下创建 posts.md:
---
title: "{{ replace .File.ContentBaseName "-" " " | title }}"
date: {{ .Date }}
author: "世界杯官方"
draft: true
---
当您运行 hugo new posts/my-first-post.md 时,Hugo 将使用 archetypes/posts.md 作为模板。
动态内容与Hugo Pipes
Hugo Pipes 是一个强大的工具集,用于处理静态资源。例如,您可以使用它来优化图片。
假设您有一个图片 static/images/hero.jpg。您可以在模板中使用 resources.Get 和 Image 方法:
{{ with resources.Get "images/hero.jpg" }}
{{ with .Fit "800x400" }}
<img src="{{ .RelPermalink }}" alt="Hero Image">
{{ end }}
{{ end }}
这会生成一个宽度为800px、高度为400px的图片。
结论
创建Hugo主题是一个循序渐进的过程。通过理解目录结构、模板继承、部分模板和Hugo Pipes,您可以构建出功能丰富且高度定制化的网站。本教程仅涵盖了基础知识,Hugo还提供了诸如分类(Taxonomies)、多语言支持、Shortcodes等更多高级功能,等待您去探索和实现。不断实践和查阅官方文档是掌握Hugo主题开发的最佳途径。