HTML 主題開發

在版本 0.6 中新增。

註記

本文件提供關於建立您自己主題的資訊。如果您僅希望使用預先存在的 HTML 主題,請參閱 HTML 主題設定

Sphinx 支援透過主題變更其 HTML 輸出的外觀。主題是 HTML 樣板、樣式表和其它靜態檔案的集合。此外,它還有一個設定檔,用於指定從哪個主題繼承、要使用哪種醒目提示樣式,以及自訂主題外觀和風格有哪些選項。

主題旨在與專案無關,因此它們可以用於不同的專案而無需變更。

註記

請參閱 Sphinx API 以取得更多可能對主題開發有幫助的資訊。

建立主題

主題的形式可以是目錄或 zip 檔案(其名稱為主題名稱),包含以下內容

  • theme.toml 檔案(首選)或 theme.conf 檔案。

  • HTML 樣板(如果需要)。

  • 一個 static/ 目錄,其中包含任何將在建置時複製到輸出靜態目錄的靜態檔案。這些可以是圖片、樣式、腳本檔案。

主題設定 (theme.toml)

theme.toml 檔案是 TOML 文件,包含兩個表格:[theme][options]

[theme] 表格定義主題的設定

  • inherit (字串):要從中繼承設定、選項、樣板和靜態檔案的基礎主題名稱。將使用來自主題「祖先」的所有靜態檔案。主題將使用繼承主題中定義的所有選項。最後,將使用繼承的主題來尋找遺失的樣板(例如,如果 "basic" 用作基礎主題,則大多數樣板將已被定義)。

    如果設定為 "none",則主題將不會從任何其他主題繼承。繼承是遞迴的,形成繼承主題的鏈(例如,default -> classic -> basic -> none)。

  • stylesheets (字串列表):將包含在產生的 HTML 標頭中的 CSS 檔案名稱列表。設定 html_style 設定值將覆寫此設定。

    包含多個樣式表的其他機制包括 CSS 中的 @import 或使用具有適當 <link rel="stylesheet"> 標籤的自訂 HTML 樣板。

  • sidebars (字串列表):側邊欄樣板列表。使用者可以透過 html_sidebars 設定值覆寫此設定。

  • pygments_style (表格):一個 TOML 表格,定義用於醒目提示語法的 Pygments 樣式名稱。該表格有兩個已識別的鍵:defaultdarkdark 鍵中定義的樣式將在 CSS 媒體查詢 (prefers-color-scheme: dark) 評估為 true 時使用。

    [theme.pygments_style.default] 可以由使用者透過 pygments_style 設定值覆寫。

[options] 表格定義主題的選項。其結構使得每個鍵值對應於變數名稱和對應的預設值。使用者可以在 html_theme_options 中覆寫這些選項,並且可以從所有樣板以 theme_<name> 的形式存取。

在版本 7.3 中新增:theme.toml 支援。

範例 theme.toml 檔案

[theme]
inherit = "basic"
stylesheets = [
    "main-CSS-stylesheet.css",
]
sidebars = [
    "localtoc.html",
    "relations.html",
    "sourcelink.html",
    "searchbox.html",
]
# Style names from https://pygments.dev.org.tw/styles/
pygments_style = { default = "style_name", dark = "dark_style" }

[options]
variable = "default value"

主題設定 (theme.conf)

theme.conf 檔案為 INI 格式 [1] (可由標準 Python configparser 模組讀取),並具有以下結構

[theme]
inherit = base theme
stylesheet = main CSS name
pygments_style = stylename
sidebars = localtoc.html, relations.html, sourcelink.html, searchbox.html

[options]
variable = default value
  • inherit 設定提供「基礎主題」或 none 的名稱。基礎主題將用於尋找遺失的樣板(如果大多數主題使用 basic 作為基礎主題,則不必提供大多數樣板),其選項將被繼承,並且也將使用其所有靜態檔案。如果您也想繼承樣式表,請透過您自己的 CSS @import 將其包含在內。

  • stylesheet 設定提供以逗號分隔的 CSS 檔案名稱列表,這些檔案名稱將在 HTML 標頭中引用。您也可以使用 CSS 的 @import 技術從另一個檔案中包含一個檔案,或使用自訂 HTML 樣板,根據需要新增 <link rel="stylesheet"> 標籤。設定 html_style 設定值將覆寫此設定。

  • pygments_style 設定提供要用於醒目提示的 Pygments 樣式名稱。使用者可以在 pygments_style 設定值中覆寫此設定。

  • pygments_dark_style 設定提供當 CSS 媒體查詢 (prefers-color-scheme: dark) 評估為 true 時要用於醒目提示的 Pygments 樣式名稱。它使用 add_css_file() 注入到頁面中。

  • sidebars 設定提供用於建構側邊欄的側邊欄樣板逗號分隔列表。使用者可以在 html_sidebars 設定值中覆寫此設定。

  • options 區段包含變數名稱和預設值對。使用者可以在 html_theme_options 中覆寫這些選項,並且可以從所有樣板以 theme_<name> 的形式存取。

在版本 1.7 中新增:側邊欄設定

在版本 5.1 中變更:stylesheet 設定接受多個 CSS 檔案名稱

轉換 theme.conftheme.toml

INI 樣式主題設定檔 (theme.conf) 可以透過 Sphinx 隨附的輔助程式轉換為 TOML。這旨在一次性使用,並且可能會在未來的 Sphinx 版本中移除,恕不另行通知。

$ python -m sphinx.theming conf_to_toml [THEME DIRECTORY PATH]

必要的引數是包含 theme.conf 檔案的目錄路徑。該程式將在同一個目錄中寫入 theme.toml 檔案,並且不會修改原始的 theme.conf 檔案。

在版本 7.3 中新增。

以 Python 套件形式發布您的主題

作為發布主題的一種方式,您可以使用 Python 套件。這讓使用者更容易設定您的主題。

若要以 Python 套件形式發布您的主題,請在您的 pyproject.toml 檔案中定義一個名為 sphinx.html_themes 的進入點,並編寫一個 setup() 函數,以使用 add_html_theme() API 註冊您的主題

# pyproject.toml

[project.entry-points."sphinx.html_themes"]
name_of_theme = "your_theme_package"
# your_theme_package.py
from pathlib import Path

def setup(app):
    app.add_html_theme('name_of_theme', Path(__file__).resolve().parent)

如果您的主題套件包含兩個或更多主題,請呼叫 add_html_theme() 兩次或更多次。

在版本 1.2 中新增:「sphinx_themes」進入點功能。

自版本 1.6 起已棄用:sphinx_themes 進入點已被棄用。

在版本 1.6 中新增:sphinx.html_themes 進入點功能。

使用 CSS 設定樣式

stylesheets 設定可用於將自訂 CSS 檔案新增至主題。

注意

HTML 元素及其類別的結構目前不是明確定義的公共 API。請從檢查已建置的 HTML 頁面中推斷它們。雖然我們無法保證完全的穩定性,但它們往往相當穩定。

依類別設定搜尋結果條目的樣式

在版本 8.0 中新增。

註記

以下命名的 CSS 類別由 Sphinx 的獨立搜尋程式碼產生。如果您使用第三方搜尋提供者(例如 ReadTheDocs)來提供搜尋結果,則可用的主題選項可能會有所不同。

搜尋結果項目具有指示搜尋詞彙找到位置的上下文的類別。您可以使用 CSS 選取器

  • ul.search li.kind-index:對於索引中的結果,例如詞彙表

  • ul.search li.kind-object:對於原始程式碼中的結果,例如 Python 函數定義

  • ul.search li.kind-title:對於在章節標題中找到的結果

  • ul.search li.kind-text:對於在文件文字中其他任何地方找到的結果

作為其他主題繼承的基礎,basic 主題有意保持最小化,並且不使用這些定義 CSS 規則。鼓勵衍生主題根據需要使用這些選取器。例如,以下樣式表將上下文圖示新增至搜尋結果列表

ul.search {
    padding-left: 30px;
}
ul.search li {
    padding: 5px 0 5px 10px;
    list-style-type: "\25A1";  /* Unicode: White Square */
}
ul.search li.kind-index {
    list-style-type: "\1F4D1";  /* Unicode: Bookmark Tabs */
}
ul.search li.kind-object {
    list-style-type: "\1F4E6";  /* Unicode: Package */
}
ul.search li.kind-title {
    list-style-type: "\1F4C4";  /* Unicode: Page Facing Up */
}
ul.search li.kind-text {
    list-style-type: "\1F4C4";  /* Unicode: Page Facing Up */
}

樣板

如果您想編寫自己的樣板,樣板指南 會很有幫助。重要的是要記住 Sphinx 搜尋樣板的順序

  • 首先,在使用者的 templates_path 目錄中。

  • 接著,在選定的主題中。

  • 然後,在其基礎主題、其基礎的基礎主題等等中。

當使用相同名稱擴展基礎主題中的樣板時,請使用主題名稱作為明確的目錄:{% extends "basic/layout.html" %}。從使用者 templates_path 樣板,您仍然可以使用「驚嘆號」語法,如 樣板文件中所述

靜態樣板

由於主題選項旨在讓使用者更輕鬆地設定主題,而無需編寫自訂樣式表,因此有必要能夠對靜態檔案以及 HTML 檔案進行樣板化。因此,Sphinx 支援所謂的「靜態樣板」,如下所示

如果主題的 static/ 目錄(或使用者靜態路徑中)的檔案名稱以 .jinja_t 結尾,則將由樣板引擎處理。後綴將從最終檔案名稱中移除。

例如,具有 static/theme_styles.css.jinja 檔案的主題可以使用樣板將選項放入樣式表。當使用該主題建置文件專案時,輸出目錄將包含一個 _static/theme_styles.css 檔案,其中所有樣板標籤都已處理。

在版本 7.4 中變更

靜態樣板的首選後綴現在是 .jinja,這與 Jinja 專案的 建議的檔案副檔名 一致。

靜態樣板的 _t 檔案後綴現在被視為「舊版」,並且支援最終可能會被移除。

如果偵測到具有 _t 後綴或 .jinja 後綴的靜態樣板,則將由樣板引擎處理,並從最終檔案名稱中移除後綴。

在 HTML 樣板中使用自訂頁面元數據

放置在頁面標題之前欄位列表 中的任何鍵/值對,在建置頁面時都將可在 Jinja 樣板中透過 meta 屬性存取。例如,如果頁面在其第一個標題之前有以下文字

:mykey: My value

My first title
--------------

那麼可以在 Jinja 樣板中像這樣存取它

{%- if meta is mapping %}
    {{ meta.get("mykey") }}
{%- endif %}

請注意檢查 meta 是否為字典(Jinja 術語中的「映射」),以確保以這種方式使用它是有效的。

定義自訂樣板函數

有時在 Python 中定義您自己的函數,然後希望在樣板中使用它會很有用。例如,如果您想插入一個樣板值,其邏輯取決於使用者在專案中的設定,或者如果您想包含非平凡的檢查並為樣板中不正確的設定提供友善的錯誤訊息。

若要定義您自己的樣板函數,您需要在模組內部定義兩個函數

  • 一個頁面上下文事件處理程序(或註冊)函數。這透過事件回呼連接到 Sphinx 應用程式。

  • 您將在 Jinja 樣板中使用的樣板函數

首先,定義註冊函數,它接受 html-page-context 的引數。

在註冊函數中,定義您想在 Jinja 中使用的樣板函數。樣板函數應傳回字串或 Python 物件(列表、字典),其中包含 Jinja 在樣板化過程中使用的字串

註記

樣板函數將可以存取傳遞給註冊函數的所有變數。

在註冊函數的末尾,使用 context['template_func'] = template_func 將樣板函數新增至 Sphinx 應用程式的上下文。

最後,在您擴展的 setup() 函數中,將您的註冊函數新增為 html-page-context 的回呼。

# The registration function
 def setup_my_func(app, pagename, templatename, context, doctree):
     # The template function
     def my_func(mystring):
         return "Your string is %s" % mystring
     # Add it to the page's context
     context['my_func'] = my_func

 # Your extension's setup function
 def setup(app):
     app.connect("html-page-context", setup_my_func)

現在,您將可以像這樣在 jinja 中存取此函數

<div>
{{ my_func("some string") }}
</div>

將您自己的靜態檔案新增至建置資產

預設情況下,Sphinx 會複製樣板目錄的 static/ 目錄中的靜態檔案。但是,如果您的套件由於某些原因需要將靜態檔案放置在 static/ 目錄之外,則需要在建置時透過事件掛鉤手動將它們複製到 HTML 輸出的 _static/ 目錄。以下是完成此操作的程式碼範例

import shutil

def copy_custom_files(app, exc):
    if app.builder.format == 'html' and not exc:
        static_dir = app.outdir / '_static'
        shutil.copyfile('path/to/myextension/_static/myjsfile.js', static_dir)

def setup(app):
    app.connect('build-finished', copy_custom_files)

根據使用者設定注入 JavaScript

如果您的擴展使用 JavaScript,則允許使用者使用其 Sphinx 設定控制其行為可能會很有用。但是,如果您的 JavaScript 以靜態函式庫的形式出現(不會使用 Jinja 建置),則這可能很難做到。

有兩種方法可以根據使用者設定將變數注入到 JavaScript 空間中。

首先,您可以將 _t 附加到擴展中包含的任何靜態檔案的末尾。這將導致 Sphinx 使用樣板引擎處理這些檔案,從而讓您可以嵌入變數並控制行為。

例如,以下 JavaScript 結構

mymodule/
├── _static
│   └── myjsfile.js_t
└── mymodule.py

將導致以下靜態檔案放置在 HTML 的建置輸出中

_build/
└── html
    └── _static
        └── myjsfile.js

請參閱 靜態樣板 以取得更多資訊。

其次,您可以使用 Sphinx.add_js_file() 方法,而無需將其指向檔案。通常,此方法用於將新的 JavaScript 檔案插入到您的網站中。但是,如果您傳遞檔案路徑,而是將字串傳遞給「body」引數,則此文字將作為 JavaScript 插入到您網站的 head 中。這允許您從 Python 將變數插入到專案的 JavaScript 中。

例如,以下程式碼將讀取使用者設定的值,然後將此值作為 JavaScript 變數插入,您的擴展的 JavaScript 程式碼可以使用該變數

# This function reads in a variable and inserts it into JavaScript
def add_js_variable(app):
    # This is a configuration that you've specified for users in `conf.py`
    js_variable = app.config['my_javascript_variable']
    js_text = "var my_variable = '%s';" % js_variable
    app.add_js_file(None, body=js_text)
# We connect this function to the step after the builder is initialized
def setup(app):
    # Tell Sphinx about this configuration variable
    app.add_config_value('my_javascript_variable', 0, 'html')
    # Run the function after the builder is initialized
    app.connect('builder-inited', add_js_variable)

因此,在您的主題中,您可以使用依賴於此變數存在的程式碼。使用者可以透過在其 conf.py 檔案中定義變數來控制變數的值。