Summary

使用Hugo从零开始搭建网站,自定义主题,包括样式。

因为想完全控制网站的功能和外观,所以写了一个符合我需要的主题。

本文只是分享完整的思路,没有囊括所有的内容,包括代码。有需要的可以fork。主要目的是分享一些认识和这个主题的特点。

创建网站

首先使用终端切换到要创建网站的文件位置,然后使用命令创建网站。

cd desktop

hugo new site example --format yml

cd example

这样就在桌面创建了一个名为example的文件夹,也就是存放网站所有内容的地方。

创建主题(theme)

一般都直接使用别人搭建好的主题,但是正如文首所说,我想要完全的控制,所以就自己建一个。

hugo new theme nth

这里我就创建了一个名为nth的主题。

后边搭建网站的过程几乎都是在编辑这个主题,它位于/example/themes/nth.

编辑主题

我是分成两部分来完成:

  • 一个是实现网站的功能,主要是编辑layouts下边的各个html文件;

    人体的骨架撑起了整个人体,各个器官配合实现了人体的正常运转。所以网站的功能架构也是这样,先搭一个框架,再整合各个功能就可以了。

  • 另一部分是实现想要的外观,这个是编辑assets下边的css。

    外观样式就类似于人类的皮肤外貌。

功能 - 主体框架

文件位于/example/themes/nth/layouts/_default/baseof.html。

<!DOCTYPE html>
<html lang="{{ site.LanguageCode }}">
    <head>
        {{- partial "head.html" . -}}
    </head>
    <body>
       <header class="header">
            {{- partial "header.html" . -}}
        </header>
        <main class="main">
            {{- block "main" . }}{{- end }}
        </main>
        <footer class="footer">
            {{- partial "footer.html" . -}}
        </footer>
    </body>
</html>

hugo会自动生成这个文件,至此,整体框架已经搭好了,下一步需要做的,就是丰富各项功能,也就是这里partialblock的各个部分:

  • head.html
  • header.html
  • main
  • footer.html

功能 - head.html

这部分的内容在网站上肉眼不可见,是给搜索引擎和浏览器看的数据。文件位于:/example/themes/nth/layouts/partials/head.html。

<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<!-- 其他需要添加的功能 -->

<!-- 下方这段是留给用户添加自定义的内容 -->
{{- partial "extend_head.html" . -}}

功能 - header.html

这部分内容一般是网页的导航栏,顶部标语等。文件位于:/example/themes/nth/layouts/partials/header.html。

<div class="top-banner"></div>

<nav>
    <!-- 其他需要添加的功能 -->
</nav>

功能 - footer.html

这部分内容一般是网页的版权,联系信息等。文件位于:/example/themes/nth/layouts/partials/footer.html。

<footer>
    <!-- 其他需要添加的功能 -->

    <!-- 下方这段是留给用户添加自定义的内容 -->
    {{- partial "extend_footer.html" . -}}

</footer>

功能 - main

上边其他三个部分都是partial,只有main是block,这是有原因的。我们的主体编辑内容,或者是经常变动的内容,都在这一部分,其他几个部分的内容变化相对较少,你想想看你浏览的各个网页,页首和页尾应该是差不多的,变化的只是中间的内容。

list.html

这个文件的功能是展示文章列表,文件位于/example/themes/nth/layouts/_default/list.html。

{{- define "main" }}
    <!-- 添加内容 -->
{{- end }}{{- /* end main */ -}}

可以看到这里的开头就写了定义main,说明这部分的内容是处于main这个元素之下的,也就是用户看到的网页主体内容部分。

在该页面列出各个文章条目。

{{- if .Content }}
  <div class="post-list">
    {{ .Content }}
  </div>
{{- end }}
  
  {{- $pages := union .RegularPages .Sections }}
  
  {{- if .IsHome }}
  {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }}
  {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }}
  {{- end }}
  {{- $paginator := .Paginate $pages }}
  {{- $term := .Data.Term }}
  {{- range $index, $page := $paginator.Pages }}
  {{- $class := "post-entry" }}
  
  <article class="{{ $class }}">
    <!-- 文章条目 -->
  </article>
  
  {{- end }}
  
  <!-- 翻页部分 -->
 
{{- end }}

single.html

这个文件的功能是展示文章内容,文件位于/example/themes/nth/layouts/_default/single.html。

{{- define "main" }}

{{- if .Content }}
<div class="post-content">
{{ .Content }}
</div>
{{- end }}

{{- end }}{{/* end main */}}

功能 - 总结

前边的每段代码都是简单演示了各个部分的主体功能,真正实现的时候也只是在这个基础上进一步丰富,有一点我深有体会,就是把各个部分都尽量拆分做成小件,小件可以被很多其他地方复用,这样做的好处有两点:减少了代码量;维护简单,只需要更改一处,其他地方的就都跟着变化。

样式 - css

文件位于:/example/themes/nth/assets/css/main.css

这个文件就是用来样式化网站的全部内容的。

认识和feature

文章是否在首页列出

hugo.yml文件的内容是网站的整体配置,分享几点:

  • disableHugoGeneratorInject: true

    这个参数值为true会阻止在网站的部分产生hugo字样的代码,当然我理解不开启是一种对原作者的尊重和宣传。

  • summaryLength: 10

    这个参数是控制summary的字符数量的,默认是70个,你可以控制它,需要注意的地方是它是统计英文字符的。

  • params.mainSections

    文章是否在首页列出。通过这个参数与list.html的代码可以实现这点。

    比如,我有两个分类:post 和 tech,如果想让首页只展示post的文章,就可以在mainSections下只写一个post,如果想让post 和 tech的文章都展示,那就把这两个都写上。

      params:
          mainSections:
          - post
          - tech
    

    在list.html中这样写:

      {{- $pages := union .RegularPages .Sections }}
    
      {{- if .IsHome }}
      {{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }}
      {{- $pages = where $pages "Params.hiddenInHomeList" "!=" "true" }}
      {{- end }}
    
      {{- $paginator := .Paginate $pages }}
    
      {{- range $index, $page := $paginator.Pages }}
    

    通过这种方式,就可以把属于params.mainSections中的文章和不隐藏的文章在首页展示了。

单个页面添加自定义的js和css

文件:head.html,更改部分如下:

<head>
    {{- partial "head.html" . -}}

    <!-- 检查并添加自定义CSS文件 -->
    {{ with .Params.css }}
    {{ range . }}
    <link rel="stylesheet" href="{{ . | absURL }}">
    {{ end }}
    {{ end }}
    
    <!-- 检查并添加自定义JavaScript文件 -->
    {{ with .Params.js }}
    {{ range . }}
    <script src="{{ . | absURL }}" defer></script>
    {{ end }}
    {{ end }}
</head>

这部分和用户在自己的文章源数据里添加js和css结合,就可以方便的为该页面添加自定义的内容。比如这篇文章我就添加了一个自定义的js和css文件作为演示,只是他们都没有内容,你可以打开源码在<head>尾部看是否存在,名字分别是01.css和01.js。

颜色标签

在list页面各个文章条目的上方有带颜色的标签,实现方法是:

{{ if .Site.Params.showtagsinlist }}
    {{ $colors := slice "tag-bg-color-01" "tag-bg-color-02" "tag-bg-color-03" "tag-bg-color-04" }} <!-- 定义颜色数组 -->
    {{ $colorIndex := 0 }} <!-- 初始化颜色索引 -->
    
    {{ with .Params.tags }}
    <div class="entry-tags">
    <ul class="post-tags">
        {{ range . }}
        <li class="{{ index $colors $colorIndex }}">{{ . }}</li>
        {{ $colorIndex = mod (add $colorIndex 1) (len $colors) }} <!-- 循环更新颜色索引 -->
        {{ end }}
    </ul>
    </div>
    {{ end }}
{{ end }}

这里首先在hugo.yml中设置一个参数showtagsinlist,这样可以让用户控制整体是否展示标签,接下来就是设定几个颜色的名称让文章的tags去循环获取。tag-bg-color-01这些是在css中设置。

文章开头的summary

这是单独添加了一个类(class),然后设置了一些样式。具体的做法是在创建一个shortcode,文件路径为:/example/themes/nth/layouts/shortcodes/summary.html。其内容为:

<div class="post-content-summary-contain">
    <p class="post-content-summary-title">Summary</p>
    <p class="post-content-summary-content">
        {{ .Page.Params.Summary | safeHTML }}
    </p>
    
</div> 
<!--more-->

然后在实际写作的markdown文档中直接加上{{< summary >}}使用就可以了。当然css也要进行设置。

文章目录(toc)

考虑到有些文章适合有目录,有些不适合,所以把这个选择权放在了文章的源数据里,比如这篇文章就是toc: true。然后调用hugo内置的目录生成功能就好。

{{ if .Params.toc }}
{{ .TableOfContents }}
{{ end }}

在hugo.yml中我们可以配置目录的内容:

markup:
tableOfContents:
    startLevel: 1
    endLevel: 5
    ordered: false

这里就配置的是从1到5级标题都收录。

css设置

这块我也不怎么会,只是分享一个体会和几点featrue.

root使用

类似于编程里的变量,在开头设置好变量,以后在文章就使用变量,好处在于如果后期有变动需求,可以直接重新给变量赋值,这样也不用一个个的去更改了。

scroll-margin-top

因为设置了导航栏固定在页面顶部,所以会造成一个问题:点击左侧的某个导航标题总是会被遮盖住一部分,所以进行如下设置:

:target {
    scroll-margin-top: var(--nav-height);
}

这样可以让页面的上边界在导航栏下方,也就是可以正确的导航,不会出现遮挡的问题。