網站版面樣式修改記錄

記錄我對 huanlin.cc 這個網站的 Hugo 與 Docsy 主題框架做了哪些調整。

我的 huanlin.cc 網站是 host 在 Github 平台上,網頁生成工具是用 Hugo 搭配 Docsy theme。本文的目的是記錄我對此網站的 Hugo 與 Docsy 主題框架做了哪些調整。

我把所有調整或新增的檔案放在 Github 上面:docsy-customization。如果你要使用的話,只要先在你的網站安裝好 Docsy theme,然後把我的 repo 中的檔案覆蓋掉你的網站裡對應的檔案,即可套用我的自訂樣式。

文件首頁

先大概看一下 look and feel 有何差異。

入口基本上沒有太大差異,我主要是針對「文件」,也就是 docs 目錄下的頁面排版樣式來做調整。

撰寫本文時,Docsy 展示網站的 docs 首頁 長這樣:

我的網站的文件首頁:

在調整樣式的時候,我經常參考和模仿 Material for MkDocs 的網頁風格,包括顏色、字體大小等等。詳見 _variables_project.scss_styles_project.scss

左側選單

左側選單(sidebar menu)主要有兩處修改:

  • 顯示三角形箭頭圖案,方便使用者一看就知道哪些選單項目還有子項可展開,以及哪些項目是沒有子項的葉節點。
  • 記住捲軸位置。

顯示三角形箭頭圖案

Docsy 官方文件的 Navigation and Menus 的 Section menu options 一節當中有說明,只要修改 Hugo 組態檔,將 params.ui.sidebar_menu_foldable 參數設定為 true,即可令左側選單出現三角形箭頭圖案來表示可展開/摺疊的選單項目。

以下摘自我的 hugo.toml 檔案內容:

# User interface configuration
[params.ui]
# Enable to show the side bar menu in its compact state.
sidebar_menu_compact = true
# 讓左邊選單可以折疊/展開
sidebar_menu_foldable = true

儘管 Docsy theme 有提供這個選項,但是它的 展示網站 並沒有啟用此功能,再加上 Docsy 範本的 hugo.toml 檔案裡面也沒有 sidebar_menu_foldable 參數,所以我一開始就以為 Docsy 無此功能。我相信應該也有不少人跟我一樣吧,以至於 GitHub 上面的 issue #100 在我寫這篇筆記的時候都還是 open 狀態(可能後來才加入此功能,但 issue 沒人去更新了)。

記住捲軸位置

在操作 Docsy 的左邊選單時,如果在子項目之間點選切換,每點一次就會因為網頁重新載入而令左邊選單也重新整理。雖然 Docsy 會記住目前選擇的項目,並且令該項目加粗顯示,但卻不會記住捲軸位置。這會造成一個對使用者操作上的不方便,因為當左邊選單的項目很長的時候,使用者透過左邊選單區塊的垂直捲軸往下找到想要查看的文章,點選之後,左邊選單就會因為網頁重新載入而令捲軸位置回到最頂端,於是就看不到先前選取的那個項目了。

光看以上文字說明可能不好理解,但只要自行操作看看 Docsy 展示網站,應該就能發現問題所在。

針對此問題,我加了一些 JavaScript 來記住左邊選單的捲軸位置。詳情:Keep Sidebar Menu's Scroll Position

文章右邊的大綱連結

檔案:/layouts/partials/toc.html

閱讀文章時,右邊會有一個區塊顯示文章大綱連結,也就是內文的各級標題連結。

原本:

  <div class="td-toc">
    {{ . }}
  </div>

改成:

  <div style="margin-left: -2px; font-weight: 700; padding-bottom: 8px;">Table of contents</div>
  <div class="td-toc">        
    {{ . }}
  </div>  

也就是在大綱區塊上方加上一行 "Table of contents"。有些網站是用 "In this article:"。

導覽列

檔案:/layouts/partials/navbar.html

Docsy 原本是用 logo.svg 作為網站頂端導覽列的 logo 圖案,我的 logo 是 .png 格式,所以也做了修改。

原本:

  {{ with resources.Get "icons/logo.svg" -}}
    {{ ( . | minify).Content | safeHTML -}}

改成:

  {{ with resources.Get "icons/logo.png" -}}
    <img src="{{ .RelPermalink }}" class="logo-image-height">

同時必須在 /assets/scss/_styles_project.scss 檔案中加入以下樣式:

.logo-image-height {
  height: 32px;
  padding-right: 12px;
}

Blog

/layouts/blog/list.html

原本:

<p class="pt-0 mt-0">{{ .Plain | safeHTML | truncate 250 }}</p>

那個 truncate 250 的作用是取部落格貼文的前面 250 個字元來當作 "Read more" 之前的摘要。但我發現 250 個字元對中文的帖子來說太長了,不好看,所以我把它改成 100:

<p class="pt-0 mt-0">{{ .Plain | safeHTML | truncate 100 }}</p>

另外,中文語系的用詞也有點過於簡略。原本叫做「更多」,我覺得「閱讀更多」或「閱讀全文」會更好一些,故我也修改了 /i18n/zh-tw.toml。詳見:繁體中文語系檔案

/layouts/blog/content.html

原本:

{{ with .Params.author }}{{ T "post_byline_by" }} <b>{{ . | markdownify }}</b> |{{ end}}

改為:

{{ if .Params.author }}
    {{ with .Params.author }}{{ T "post_byline_by" }} <b>{{ . | markdownify }}</b> |{{ end}}
{{ else }}	
    {{ with $.Site.Params.default_blog_author }}{{ T "post_byline_by" }} <b>{{ . | markdownify }}</b> |{{ end}}
{{ end }}

同時在 hugo.toml 檔案中增加 default_blog_author 參數:

[params]
default_blog_author = "Michael Tsai" 

如此一來,每一篇部落格帖子的檔頭就不用提供 author 屬性。

/assets/scss/ 資料夾

以下分別

_variables_project.scss

檔案內容:

/*
  Add styles or override variables from the theme here.
*/

$google_font_name: "Noto Sans TC";
$google_font_family: "Noto+Sans+TC:300,300i,400,400i,700,700i";

@import "_admonition_variables";
@import "_admonition";

其中 import 的 _admonition.scss_admonition_variables.scss 也是放在同一個目錄下。這部分的細節已整理在另一篇文章:Admonitions

_styles_project.scss

CSS 樣式的部分就不解釋了,直接把檔案內容貼上來:

// This is a custom SCSS file for Hugo Docsy theme.
// See: https://www.docsy.dev/docs/adding-content/lookandfeel/#project-style-files

/*
  For MediumZoom.js to force the zoomed image to be displayed on top of everything.
  Without these settings, the zoomed image will display under some elements on the page.

  Ref: https://github.com/francoischalifour/medium-zoom#debugging
*/
.medium-zoom-overlay,
.medium-zoom-image--opened {
  z-index: 999;
}

// For admonitions. Copied from MkDocs Material (by Michael Tsai 2023-8-6).
:root > * {
  --md-shadow-z1: 0 0.2rem 0.5rem #0000000d,0 0 0.05rem #0000001a;
  --md-shadow-z2: 0 0.2rem 0.5rem #0000001a,0 0 0.05rem #00000040;
  --md-shadow-z3: 0 0.2rem 0.5rem #0003,0 0 0.05rem #00000059;

  --md-primary-fg-color: #16191F;
}

:root {
  --bs-body-font-family: Noto Sans TC, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;
  --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  
  // for mark tag
  --line-yellow: url("data:image/svg+xml;charset=utf-8,%3Csvg preserveAspectRatio='none' width='120' height='6' viewBox='0 0 120 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M119 0.8C60 4 50-0.5 1 1.5' stroke='%23fc0' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
}

.logo-image-height {
  height: 32px;
  padding-right: 12px;
}

pre {
  font-size: 0.9rem;
}

h2 {
  font-size: 1.9rem;  
  font-weight: 600;
}

h2.feedback--title {
  padding-top: 2rem;
  font-size: 1.7rem;  
  font-weight: 500;
  color: var(--md-primary-fg-color);
}

// Section 首頁的標題連結
.section-index h5 a {
  font-weight: 700;
  font-family: '微軟正黑體', var(--bs-body-font-family);
  font-size: 1.18rem;
}

.lead {
  font-size: 1.1rem;
  font-weight: 400;
}

.reading-time {
  margin-top: 20px;
} 

.td-toc a {
  font-weight: 400;
}

.td-max-width-on-larger-screens {
  @include media-breakpoint-up(lg) {
    max-width: 95%; /* Docsy 預設為 80% */
  }
}

@media (min-width: 1200px) {
  // 左邊主選單的寬度
  .col-xl-2 {
    flex: none;
    width: 19%; // 原本為 16.66666667%
  }

  // 中間內文區域的寬度
  .col-xl-8 {
    flex: 0 0 auto;
    width: 60%; // 原本為 66.66666667%;
  }
}

// Docsy 預設的選單字型太大,顏色太淺,此處略作調整。
.td-sidebar-nav .td-sidebar-link {
  color: var(--md-primary-fg-color);
  display: block;
  padding-bottom: 0.375rem;
  font-size: 0.95rem;
  font-weight: 400;
}

// 左邊選單的子項目縮排
@media (min-width: 768px) {
  .td-sidebar-nav__section .ul-1 ul {
    padding-left: 1.2em;
  }
}

// 右邊的 table of contents 的樣式
.td-toc #TableOfContents a {
  color: var(--md-primary-fg-color);
  font-size: 0.9rem;
}

// 右邊的 table of contents 區塊的子標題縮排
.td-toc li li {
  margin-left: 0.9rem;
}

// 右邊的 table of contents 區塊的位置保持固定
@supports (position: sticky) {
.td-sidebar-toc {
    position: sticky;
    top: 6rem;
    height: calc(100vh - 6rem);
    overflow-y: auto;
  }
}

// 頁面頂端標題列(導覽列),樣式取自 Material for MkDocs。
.td-navbar {
  background: var(--md-primary-fg-color); // #30638e;

  // 下方加上陰影
  box-shadow: 0 0 0.2rem #0000001a, 0 0.2rem 0.4rem #0003;
  transition: transform .25s cubic-bezier(.1,.7,.1,1),box-shadow .25s;
}

// 頂端導覽列的字體
.td-navbar .nav-link {
    text-transform: none;
    font-weight: 500;
    font-size: 1.05rem;
}

// The outer page container for the default base template.
.td-default {
  main {
    > section:first-of-type {
      @include media-breakpoint-up(md) {
        padding-top: 1rem; // by Michael: 原本是 8rem
      }
    }

    section {
      @extend .td-block-padding;
    }
  }
}

// img[src$="#center"] 用來將圖片置中
img[src$="#center"] {
  display: block;
  margin: 1.0rem auto;
  max-width: 100%;
  height: auto;
}

// Mark tag as a yellow underline.
mark {
  color: inherit;
  background: var(--line-yellow) bottom left/100% 0.3em no-repeat;
  text-decoration: none;
  padding-bottom: 0.3em;
}

繁體中文語系檔案

底下是我修改的繁體中文語系檔案 /i18n/zh-tw.toml 的內容:

[ui_search]
other = "站內搜尋…"

[post_reading_time]
other = " 分鐘左右可讀完"
[post_less_than_a_minute_read]
other = "1 分鐘內可讀完"

[post_last_mod]
other = "Last update"

[post_byline_by]
other = "作者:"

[ui_read_more]
other = "閱讀全文"

說明:

  • [post_byline_by] 是用於部落格文章的作者姓名之前的標籤文字。若使用 Docsy 原本的檔案,顯示作者姓名的時候會像這樣:藉由 Michael
  • [ui_read_more] 在英文語系檔案裡面的用詞是 "Read more",可是到了中文語系的檔案裡面卻是「更多」——只有 more,沒了 read 動作。
  • [post_last_mod] 我決定使用英文 "Last update"。

如欲取得完整檔案內容,可以從我的 Docsy fork 下載 zh-tw.toml

Last modified: April 15, 2024