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 (表): 定义用于语法高亮的 Pygments 样式名称的 TOML 表。该表有两个可识别的键:
default
和dark
。dark
键中定义的样式将在 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.pythonlang.cn/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.conf
为 theme.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’ entry_points 功能。
自 1.6 版本弃用: sphinx_themes
entry_points 已被弃用。
1.6 版本新增: sphinx.html_themes
entry_points 功能。
使用 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 术语中为“mapping”),以确保以这种方式使用它是有效的。
定义自定义模板函数¶
有时,在 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 插入到你站点的头部。这允许你从 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
文件中定义它来控制变量的值。