快轉到主要內容

模板系統

查看原始碼編輯此頁 (外部連結)

本文介紹 Hugo 的模板查找機制,查找機制決定每個頁面該套用哪個模板,主要由三個基本概念決定:page kind、page type,以及 front matter 手動指定的 layout。理解基本概念之後,我們會介紹完整的模板分類,才真正說明完整的查找順序,在文章的最後搭配兩個範例總結本文。



Page Kind 此標題的連結

Page Kind 概念和 content 目錄結構的概念完全相同:

  • home:網站首頁
  • page:單一內容頁面,舊版稱作 single
  • section:區段列表頁,舊版稱作 list
  • taxonomy:某個分類法(taxonomy)底下所有詞條(term)的列表頁,例如 /tags/。
  • term:分類法底下單一詞條的頁面

content/ 目錄結構與 page kind 的對應關係:

content/
content
├── _index.md       # 對應 layouts/home.html
├── docs
│   ├── _index.md   # 對應 layouts/section.html
│   └── p1.md       # 對應 layouts/page.html
│
└── tags
    ├── _index.md   # 對應 layouts/taxonomy.html
    └── my-tag.md   # 對應 layouts/term.html

Page Type 此標題的連結

決定 page kind 之後,Hugo 接著會判斷 page type,用來決定同一種 kind 底下要套用哪一組模板。

舉例來說,同樣是 page kind,content/posts/ 與 content/movies/ 底下的文章,可以透過不同的 type 套用不同模板:

layouts/
layouts/
├── movies/
│   ├── page.html      # movies 專用的 page 模板
│   └── section.html   # movies 專用的 section 模板
├── home.html
├── section.html
├── taxonomy.html
├── term.html
└── page.html

Type 的預設值等於內容所在的目錄名稱。例如 content/movies/p1/index.md 的 type 會預設為 movies。你也可以透過 front matter 的 type 欄位手動指定:

content/movies/p1/index.md
---
title: '我的文章'
type: 'posts'
---

Layout 此標題的連結

除了 kind 與 type,你也可以直接在 front matter 用 layout 欄位指定模板檔名:

---
title: '我的文章'
layout: 'custom'
---

這會對應到:

layouts/
├── custom.html    # 由 layout: custom 指定
├── home.html
├── section.html
├── taxonomy.html
├── term.html
└── page.html

layout 欄位的優先權高於依 kind 或 type 自動判斷的結果。

提示

三種分類方式的簡單理解:

  1. page kind 判斷頁面類型,例如標籤頁或一般文章頁
  2. page type 進一步細分,讓不同 type 套用不同模板
  3. layout 由 front matter 手動指定,適合 about、privacy 這類獨立頁面

模板分類 此標題的連結

本段落介紹 layouts 目錄底下的模板分類,包含基礎模板、頁面模板等重要內容。

layouts 目錄總覽 此標題的連結

layouts/ 目錄存放渲染網站的模板,結構總覽如下

layouts 目錄總覽
layouts/
├── baseof.html     # 基礎模板
├── page.html       # kind: page
├── home.html       # kind: home
├── section.html    # kind: section
├── taxonomy.html   # kind: taxonomy
├── term.html       # kind: term
├── single.html     # page 的後備模板
├── list.html       # home / section / taxonomy / term 的後備模板
├── all.html        # 所有頁面模板的最終後備模板
├── _markup/        # 設定 Markdown 元素的渲染方式(render hook)
├── _shortcodes/    # 供內容頁面呼叫,不屬於頁面模板
└── _partials/      # 可重用區段,不屬於頁面模板

本段落會介紹 layouts/ 的所有內容。

基礎模板 此標題的連結

基礎模板就是 baseof.html,是所有頁面模板共用的外層架構,通常定義 html、head、body 等共通結構,以維持一致性,讓網站更容易維護。

基礎模板中通常會使用 block (外部連結) 函數,當符合條件時,block 函數就會使用頁面模板中的指定區塊渲染,條件為:

  • 頁面模板需包含 define
  • 頁面模板不能包含能直接被渲染的內容

若不符合條件,基礎模板會被忽略,該檔案直接使用頁面模板渲染。基礎模板和頁面模板的使用範例如下:

layouts/baseof.html
<!DOCTYPE html>
<html lang="{{ site.Language.Locale }}">
<body>
  <main>
    {{ block "main" . }}
      這段內容會被套用此基礎模板的頁面模板中,
      對應的 define "main" 取代。
    {{ end }}
  </main>
</body>
</html>
layouts/home.html
{{ define "main" }}
  這段內容會取代基礎模板裡的 block "main"。
  {{ template "inlineTemplate" }}
{{ end }}

{{/* 只允許空白、註解放在外部 */}}

{{ define "inlineTemplate" }}
  Inline define 是被允許的,因為它不會被直接渲染。
{{ end }}

頁面模板 此標題的連結

頁面模板渲染的內容和 page kind 一一對應,包含

  • layouts/home.html
  • layouts/page.html
  • layouts/section.html
  • layouts/taxonomy.html
  • layouts/term.html

以及後備選項

  • layouts/single.html 是 page 模板的後備選項
  • layouts/list.html 是 home、section、taxonomy、term 模板的後備選項
  • layouts/all.html 是所有頁面模板的後備選項

其他模板 此標題的連結

除了頁面模板,Hugo 還包含下列用途較特定的模板類型:

Render hook 此標題的連結

Render hook 讓你自訂 Markdown 指定元素轉換成 HTML 的方式,例如自訂圖片、連結、標題等元素的輸出結果。Render hook 放在 _markup/ 目錄下,支援以下類型:

_partials 目錄 此標題的連結

layouts/_partials 底下放可重用的模板片段,用 partial 函數呼叫。以渲染 layouts/_partials/head.html 為例:

{{ partial "head.html" . }}

第一個參數是模板名稱,二個參數 . 是傳入的 context。

_shortcodes 目錄 此標題的連結

layouts/_shortcodes 底下放供 Markdown 呼叫的模板,用於在 Markdown 內容裡插入結構化元件,例如嵌入音訊、影片,或其他 HTML 區塊。

View 此標題的連結

View (外部連結) 模板用於自動在不同頁面使用不同模板,而不是和 partial 一樣以指定的固定模板渲染。

View 模板必須以 .Render 渲染,查找規則與 Hugo 的模板查找順序相同。

查找順序 此標題的連結

最基礎的優先級判斷如下:

  1. front matter 手動指定的 layout
  2. 對應 page kind 的專用模板(home、section、taxonomy、term、page)
  3. page 的後備模板 single,或 home / section / taxonomy / term 的後備模板 list
  4. all.html 最終後備模板

這是只使用基礎概念的範例,實際上 Hugo 支援更複雜的查找規則:檔名可以用 . 分隔條件,且模板放置的目錄深度同樣會影響優先權。以下分別說明。

以 . 分隔條件 此標題的連結

使用 . 分隔的檔名讓模板能同時過濾多個條件,包含語言、輸出格式、page kind 等等,在檔名中用 . 分隔各項條件即可:

# section 頁面,德語專用
section.de.html

# 主頁 JSON 輸出,德語,v2.0.0 專用
home.de._version_v2.0.0_.json

條件包含

在 v0.161.0 (外部連結) 之後,你可以用更精確的方式標記,比如 home._outputformat_rss_.xml、section._language_de_.html、baseof._kind_section_._language_de_.html。

路徑深度 此標題的連結

路徑匹配越接近目前渲染的內容,優先權越高,且路徑深度的優先權高於檔名條件,只有當兩者路徑距離相同時,才會回頭比較檔名條件的比對結果。

支援情況 此標題的連結

不同模板類型對進階查找順序的支援各有不同,表格整理如下:

Page Kind輸出格式語言路徑深度
基礎模板支援支援支援支援
頁面模板支援支援支援支援
Render hook❌支援支援支援
Shortcode❌支援支援❌
Partial❌❌❌❌
View❌❌❌不適用

一個完整網站的範例 此標題的連結

以下用兩個範例,展示本篇介紹的所有模板類型在實際專案中會如何組合出現。

簡單網站 此標題的連結

最基礎的網站只需要一個基礎模板,搭配每種 page kind 各一份頁面模板。

layouts/
├── baseof.html
├── home.html
├── page.html
├── section.html
├── taxonomy.html
├── term.html
├── _markup/
│   └── render-image.html
├── _partials/
│   ├── header.html
│   └── footer.html
└── _shortcodes/
    └── audio.html

複雜網站 此標題的連結

規模較大的網站,可能需要針對特定 type 或 section 使用專屬模板與 render hook,用 view 依情境渲染同一批內容的不同呈現方式。

layouts/
├── baseof.html
├── home.html
├── page.html
├── section.html
├── taxonomy.html
├── term.html
├── all.html
├── custom.html
├── movies/
│   ├── page.html
│   ├── _views/
│   │   └── card.html
│   ├── section.html
│   ├── _markup/
│   │   └── render-image.html
│   └── action/
│       ├── page.html
│       └── _markup/
│           └── render-image.html
├── films/
│   ├── _views/
│   │   └── card.html
│   ├── page.html
│   └── section.html
├── _markup/
│   └── render-image.html
├── _partials/
│   ├── header.html
│   └── footer.html
└── _shortcodes/
    └── audio.html

無障礙設定

字體大小