hugo搭建个人博客4-主题美化

警告
本文最后更新于 2020-02-12,文中内容可能已过时。

1. 基础知识

通过一个简单的主题开发流程,理解需要的基本知识,为自己进行主题修改和美化打基础,这里参考create a new theme一文。

开发准备

Ubuntu安装hugo

1
2
$ snap install hugo --channel=extended
hugo (extended/stable) 0.58.3 from Hugo Authors installed

该命令将安装extendedSass/SCSS版本(apt-get 安装的hugo版本较低)

建立博客文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
$ hugo new site newTheme
$ ls -l
total 28
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 archetypes
-rw-r--r-- 1 shuzang shuzang   82 Sep 25 15:52 config.toml
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 content
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 data
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 layouts
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 static
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:52 themes

创建主题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ hugo new theme LeaveIt
$ find themes -type f | xargs ls -l
-rw-r--r-- 1 shuzang shuzang    8 Sep 25 16:09 themes/LeaveIt/archetypes/default.md
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/404.html
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/_default/list.html
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/_default/single.html
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/index.html
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/partials/footer.html
-rw-r--r-- 1 shuzang shuzang    0 Sep 25 16:09 themes/LeaveIt/layouts/partials/header.html
-rw-r--r-- 1 shuzang shuzang 1081 Sep 25 16:09 themes/LeaveIt/LICENSE.md
-rw-r--r-- 1 shuzang shuzang  436 Sep 25 16:09 themes/LeaveIt/theme.toml

find themes -type f将themes目录及其子目录的所有一般文件列出

xargs ls -lfind命令基础上列出这些文件的基本信息

LeaveIt 包含 templates (以 .html为后缀的文件), license 文件, 主题描述 (theme.toml 文件), 和一个空的archetype.

license文件默认填充MIT协议

根据引号中的描述编辑theme.toml文件,声明主题基本信息,参照hugoThemes的说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ nano themes/LeaveIt/theme.toml
name = "Theme Name"
license = "MIT"
licenselink = "Link to theme's license"
description = "Theme description"
homepage = "Website of your theme"
tags = ["blog", "company"]
features = ["some", "awesome", "features"]
min_version = "0.57.0"

[author]
    name = "Your name"
    homepage = "Your website"

# If porting an existing theme
[original]
    author = "Name of original author"
    homepage = "His/Her website"
    repo = "Link to source code of original theme"

编辑config.toml文件,在文件名添加theme字段,启用主题

1
2
3
4
5
$ nano config.toml
baseURL = "http://example.org/"
languageCode = "en-us"
title = "My New Hugo Site"
theme = "LeaveIt"

重新生成网站,public文件夹和themes/LeaveIt都将生成js和css文件夹用于控制格式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
$ hugo --verbose
$ ls -l public
total 24
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:56 categories
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 css
-rw-r--r-- 1 shuzang shuzang  468 Sep 25 16:43 index.xml
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 js
-rw-r--r-- 1 shuzang shuzang  437 Sep 25 16:43 sitemap.xml
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 15:56 tags
$ find themes/LeaveIt -type d | xargs ls -ld
drwxr-xr-x 5 shuzang shuzang 4096 Sep 25 16:32 themes/LeaveIt
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/archetypes
drwxr-xr-x 4 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/layouts
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/layouts/_default
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/layouts/partials
drwxr-xr-x 4 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/static
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/static/css
drwxr-xr-x 2 shuzang shuzang 4096 Sep 25 16:09 themes/LeaveIt/static/js

开发流程

删除public文件夹,执行hugo server命令并添加–watch参数,打开浏览器查看网站,修改主题文件,浏览器页面将会实时更改

建议:不要直接在主题上开发,使用git,在开发分支开发,确认功能无误后合并到主分支

1
2
3
4
# 删除public文件夹
$ rm -rf public
# 以watch模式实时查看改动
$ hugo server --watch --verbose

更新Home Page 模板,位于layout/目录下:

  • index.html
  • _default/list.html
  • _default/single.html

现在,模板文件是空的,添加以下内容到模板文件

1
2
3
4
5
6
$ nano themes/LeaveIt/layouts/index.html
<html> 
<body> 
  <p>hugo says hello!</p> 
</body> 
</html>

浏览器将显示p标签中的语句

hugo中有三种类型的模板,home页面模板刚刚已修改,single类型的模板用于生成单个内容的文件,list类型的模板用于生成多个内容的文件,即single.html和list.html

还存在partial,content views和terms三种类型的模板,这里不做详细介绍。

更新index.html使之能显示主页

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<html>
<body>
  {{ range first 10 .Data.Pages }}
    <h1>{{ .Title }}</h1>
  {{ end }}
</body>
</html>

hugo使用Go模板引擎,引擎将扫描模板文件中”{{“和”}}“中间的命令内容并执行,上面的index.html文件中包含三个命令

  1. range
  2. .Title
  3. end

range是迭代器,用于遍历前十个page,hugo创建的每个html文件都属于page,所以遍历pages将查看创建的每个文件

.Title打印title变量的值,hugo从markdown文件前面的格式说明中获取该值

end结束range开启的迭代

hugo会在创建html文件前将所有内容加载到变量中,然后模板对其进行处理

因此,更新后的index.html文件将显示first.md和second.md两篇博文的标题

到此开发一个主题的所有知识就全部介绍完毕了,剩下的就是熟悉Go模板的命令及使用它。但这里还有一些内容可以令我们更容易地创建模板

修改single.html文件使之展示博文内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<!DOCTYPE html>
<html>
<head>
  <title>{{ .Title }}</title>
</head>
<body>
  <h1>{{ .Title }}</h1>
  {{ .Content }}
</body>
</html>

修改index.html为博文标题标题添加链接

1
2
3
4
5
6
7
8
<!DOCTYPE html>
<html>
<body>
  {{ range first 10 .Data.Pages }}
    <h1><a href="{{ .Permalink }}">{{ .Title }}</a></h1>
  {{ end }}
</body>
</html>

在content目录创建about.md文件,作为主页面顶级菜单

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
+++
title = "about"
description = "about this site"
date = "2014-09-27"
slug = "about time"
+++

## about us

i'm speechless

浏览器主页面将显示about菜单,单击即可跳转查看其内容,但它和博文标题放在一起,因此修改index.html文件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<body>
  <h1>posts</h1>
  {{ range first 10 .Data.Pages }}
    {{ if eq .Type "post"}}
      <h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
    {{ end }}
  {{ end }}

  <h1>pages</h1>
  {{ range .Data.Pages }}
    {{ if eq .Type "page" }}
      <h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
    {{ end }}
  {{ end }}
</body>
</html>

主页面将分两部分显示:博文和页面。并链接到不同的页面。

改变配置文件中的permalinks,设置页面名

1
2
3
[permalinks]
	page = "/:title/"
	about = "/:filename/"

如果模板文件存在重叠,可以把重叠部分以共享模板的形式放在themes/LeaveIt/layouts/partials/目录。通常,模板文件引用都会有一个指定的路径,但是partials没有,hugo会沿着TODO定义的搜索路径去使用,因此可以编辑这里的内容来覆盖主题的表达。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
$ vi themes/LeaveIt/layouts/partials/header.html
<!DOCTYPE html>
<html>
<head>
	<title>{{ .Title }}</title>
</head>
<body>

$ vi themes/LeaveIt/layouts/partials/footer.html
</body>
</html>

partials和普通模板调用的不同是没有路径,比如

1
2
3
{{ template "theme/partials/header.html" . }}
vs
{{ partial "header.html" . }}

更新index.html文件内容

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{{ partial "header.html" . }}

  <h1>posts</h1>
  {{ range first 10 .Data.Pages }}
    {{ if eq .Type "post"}}
      <h2><a href="{{ .Permalink }}">{{ .Title }}</a></h2>
    {{ end }}
  {{ end }}

  <h1>pages</h1>
  {{ range .Data.Pages }}
    {{ if or (eq .Type "page") (eq .Type "about") }}
      <h2><a href="{{ .Permalink }}">{{ .Type }} - {{ .Title }} - {{ .RelPermalink }}</a></h2>
    {{ end }}
  {{ end }}

{{ partial "footer.html" . }}

更新single.html文件

1
2
3
4
5
6
{{ partial "header.html" . }}

  <h1>{{ .Title }}</h1>
  {{ .Content }}

{{ partial "footer.html" . }}

此时浏览器中主页面about菜单将额外展示类型和标题

更新single.html文件,添加对博文日期的渲染

1
2
3
4
5
6
7
{{ partial "header.html" . }}

  <h1>{{ .Title }}</h1>
  <h2>{{ .Date.Format "Mon, Jan 2, 2006" }}</h2>
  {{ .Content }}

{{ partial "footer.html" . }}

此时浏览器博文页面将展示创建日期

有多种方式使日期只展示在博文页面中,一种是在index.html中添加if条件语间,另一种是为博文创建单独的模板。当主题比较复杂时,创建针对博文的单独模板

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
$ mkdir themes/LeaveIt/layouts/post
$ nano themes/LeaveIt/layouts/_default/single.html
{{ partial "header.html" . }}

  <h1>{{ .Title }}</h1>
  {{ .Content }}

{{ partial "footer.html" . }}
$ nano themes/LeaveIt/layouts/post/single.html
{{ partial "header.html" . }}

  <h1>{{ .Title }}</h1>
  <h2>{{ .Date.Format "Mon, Jan 2, 2006" }}</h2>
  {{ .Content }}

{{ partial "footer.html" . }}

移除了默认的single模板中对日期的指定,而在post的single模板添加

至此对主题的基本结构有了了解,接下来应该进一步学习Hugo中Go模板的语法,参见Introduction to Go Templates

注意,以下的调整都是对原主题样式的调整,需要修改主题源码,因此最好clone主题仓库进行开发。

2. 调整引用样式

主题原有的引用样式如下

引用样式示例

修改assets/css/_common/_core/base.scss文件如下调整引用样式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  }

  blockquote {
-    font-size: 1rem;
-    display: block;
-    border-width: 1px 0;
-    border-style: solid;
-    border-color: $light-border-color;
-    padding: 1.5em 1.2em 0.5em 1.2em;
-    margin: 0 0 2em 0;
-    position: relative;
-
-    &:before {
-      content: '\201C';
-      position: absolute;
-      top: 0em;
-      left: 50%;
-      transform: translate(-50%, -50%);
-      width: 3rem;
-      height: 2rem;
-      font: 6em/1.08em 'PT Sans', sans-serif;
-      color: $light-post-link-color;
-      text-align: center;
-
-       .dark-theme &{
-         color: $dark-post-link-color;
-       }
-    }
-    &:after {
-      content: "#blockquote" attr(cite);
-      display: block;
-      text-align: right;
-      font-size: 0.875em;
-      color: $light-post-link-color;
-
-       .dark-theme &{
-         color: $dark-post-link-color;
-       }
-    }
+    font: 14px/22px normal helvetica, sans-serif;
+    margin-top: 10px;
+    margin-bottom: 10px;
+    margin-left: 2%;
+    margin-right: 0%;
+    padding-left: 15px;
+    padding-top: 10px;
+    padding-right: 10px;
+    padding-bottom: 10px;
+    border-left: 3px solid #ccc;
+    background-color:#f1f1f1;  

    .dark-theme & {
-      border-color: $dark-border-color;
+      background-color:#252529;
    }
  } 

3. 添加阅读进度条

首先在layouts/partials/header.html文件中如下所示插入代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<nav class="navbar">
+    {{ if (and .IsPage (not .Params.notsb)) }}
+        <div class="top-scroll-bar"></div>
+    {{ end }}
    <div class="container">
        <div class="navbar-header header-logo">
        	<a href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a>
@@ -13,7 +16,10 @@
    </div>
</nav>
<nav class="navbar-mobile" id="nav-mobile" style="display: none">
+    {{ if (and .IsPage (not .Params.notsb)) }}
+        <div class="top-scroll-bar"></div>
+    {{ end }}
    <div class="container">
        <div class="navbar-header">
            <div>  <a href="javascript:void(0);" class="theme-switch"><i class="iconfont icon-sun"></i></a>&nbsp;<a href="{{.Site.BaseURL}}">{{ .Site.Title }}</a></div>
            <div class="menu-toggle">

然后在assets/css/_cusstom.scss文件中添加进度条样式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// 顶部阅读进度条
.top-scroll-bar {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 9999;
    display: none;
    width: 0;
    height: 3px;
    background: #ef3982;
  } 

之后新建一个 js 脚本文件 assets/js/_custom.js ,来控制进度条

1
2
3
4
5
6
// 顶部阅读进度条
$(document).ready(function () {
    $(window).scroll(function(){
      $(".top-scroll-bar").attr("style", "width: " + ($(this).scrollTop() / ($(document).height() - $(this).height()) * 100) + "%; display: block;");
    });
  }); 

最后, js 脚本引入到博客中,使其生效。

/layouts/partials/js.html 文件中添加以下内容,然后将 $custom 加入到变量 $vendorscript

1
{{ $custom := resources.Get "/js/_custom.js" }}

重新编译后预览博客就可以看到阅读进度条了。

4. 添加侧边栏目录

原本LeaveIt主题不支持文章目录导航,可以按如下方法添加,但样式不是很合适

首先在/assets/css/_custom.scss添加侧边栏目录(toc)样式

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// 添加toc栏
  .post-toc {
    position: absolute;
    width: 200px;
    margin-left: 800px;
    padding: 10px;
    word-wrap: break-word;
    box-sizing: border-box;

    .post-toc-title {
        margin: 0;
        font-weight: 400;
        text-transform: uppercase;
    }

    .post-toc-content {
        &.always-active ul {
            display: block;
        }

        >nav>ul {
            margin: 10px 0;
        }

        ul {
            padding-left: 0;
            list-style: none;

            ul {
            padding-left: 15px;
            display: none;
            }

            .has-active > ul {
                display: block;
            }
        }
    }

    a:hover {
        color: #c05b4d;
        -webkit-transform: scale(1.1);
        -ms-transform: scale(1.1);
        transform: scale(1.1);
    }

    a {
        display: block;
        line-height: 30px;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        -webkit-transition-duration: .2s;
        transition-duration: .2s;
        -webkit-transition-property: -webkit-transform;
        transition-property: -webkit-transform;
        transition-property: transform;
        transition-property: transform,-webkit-transform;
        -webkit-transition-timing-function: ease-out;
        transition-timing-function: ease-out;
    }
}
@media only screen and (max-width: 1224px) {
    .post-toc {
        display: none;
    }
} 

然后在 layouts/partials/ 下新建 toc.html 文件,内容如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<div class="post-toc" id="post-toc">
  <h2 class="post-toc-title">{{ T "toc" }}</h2>
  {{ $globalAutoCollapseToc := .Site.Params.autoCollapseToc | default false }}
  <div class="post-toc-content{{ if not (or .Params.autoCollapseToc (and $globalAutoCollapseToc (ne .Params.autoCollapseToc false))) }} always-active{{ end }}">
    {{.TableOfContents}}
  </div>
</div>

<script type="text/javascript">
  window.onload = function () {
    var fix = $('.post-toc');
    var end = $('.post-comment');
    var fixTop = fix.offset().top, fixHeight = fix.height();
    var endTop, miss;
    var offsetTop = fix[0].offsetTop;
    $(window).scroll(function () {
      var docTop = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
      if (end.length > 0) {
        endTop = end.offset().top;
        miss = endTop - docTop - fixHeight;
      }
      if (fixTop < docTop) {
        fix.css({ 'position': 'fixed' });
        if ((end.length > 0) && (endTop < (docTop + fixHeight))) {
          fix.css({ top: miss });
        } else {
          fix.css({ top: 0 });
        }
      } else {
        fix.css({ 'position': 'absolute' });
        fix.css({ top: offsetTop });
      }
    })
  }
</script>  

在文章页的模板 layouts/_default/single.html</header>标签后引入toc模板

1
2
3
 {{ if ( .Site.Params.toc | default true ) }}
     {{ partial "toc.html" . }}
 {{ end }}

添加后重新使用hugo生成静态页面,只要文章有多级标题,就能在侧边栏看到导航目录

最后在站点配置文件config.toml中添加如下配置

1
2
toc = true                # 是否开启目录
autoCollapseToc = true   # Auto expand and collapse toc

5. 图片添加阴影

assets/css/style.scss中添加以下代码

1
2
3
4
5
6
7
// 图片阴影
.post-content {
	img {
        box-shadow: 0 0 15px 5px rgba(0, 0, 0, .28);
        max-width: 1080px;
	}
}
支付宝
微信
0%