Desenvolvimento de tema HTML

Adicionado na versão 0.6.

Nota

Este documento fornece informações sobre como criar seu próprio tema. Se você simplesmente deseja usar temas HTML pré-existentes, consulte o HTML theming.

O Sphinx tem suporte à alteração da aparência de sua saída HTML através do temas. Um tema é uma coleção de modelos HTML, folhas de estilo e outros arquivos estáticos. Além disso, ele possui um arquivo de configuração que especifica de qual tema herdar, qual estilo de realce usar e quais opções existem para personalizar a aparência do tema.

Temas são independentes de projetos e podem ser usados em diversos projetos em modificação.

Nota

Veja API do Sphinx para mais informações que podem ser úteis no desenvolvimento de temas.

Criando temas

Os temas assumem a forma de um diretório ou de um arquivo zip (cujo nome é o nome do tema), contendo o seguinte:

  • Um arquivo theme.toml (preferencial) ou um arquivo theme.conf.

  • Modelos HTML, se necessário.

  • Um diretório static/ contendo todos os arquivos estáticos que serão copiados para o diretório estático de saída na construção. Estes podem ser imagens, estilos, arquivos de script.

Configuração do tema (theme.toml)

O arquivo theme.toml é um documento TOML, contendo duas tabelas: [theme] e [options].

A tabela [theme] define as configurações do tema:

  • inherit (string): O nome do tema base do qual vai se herdar configurações, opções, modelos e arquivos estáticos. Todos os arquivos estáticos dos ‘ancestrais’ do tema serão usados. O tema utilizará todas as opções definidas nos temas herdados. Finalmente, os temas herdados serão usados ​​para localizar modelos ausentes (por exemplo, se "basic" for usado como tema base, a maioria dos modelos já estará definida).

    Se definido como "none", o tema não herdará de nenhum outro tema. A herança é recursiva, formando uma cadeia de temas herdados (por exemplo, default -> classic -> basic -> none).

  • stylesheets (lista de strings): Uma lista de nomes de arquivos CSS que serão incluídos no cabeçalho HTML gerado. Definir o valor de configuração html_style substituirá esta configuração.

    Outros mecanismos para incluir múltiplas folhas de estilo incluem @import em CSS ou usar um modelo HTML personalizado com tags <link rel="stylesheet"> apropriadas.

  • sidebars (lista de strings): Uma lista de modelos de barra lateral. Isto pode ser substituído pelo usuário através do valor de configuração html_sidebars.

  • pygments_style (tabela): Uma tabela TOML que define os nomes dos estilos Pygments a serem usados ​​para realçar a sintaxe. A tabela possui duas chaves reconhecidas: default e dark. O estilo definido na chave dark será usado quando a media query CSS (prefers-color-scheme: dark) for avaliada como verdadeira.

    [theme.pygments_style.default] pode ser substituído pelo usuário através do valor de configuração pygments_style.

A tabela [options] define as opções para o tema. Está estruturado de forma que cada par de chave-valor corresponda a um nome de variável e ao valor padrão correspondente. Estas opções podem ser substituídas pelo usuário em html_theme_options e são acessíveis a partir de todos os modelos como theme_<nome>.

Adicionado na versão 7.3: Suporte a theme.toml.

Exemplo de arquivo theme.toml:

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

[options]
variable = "default value"

Configuração do tema (theme.conf)

O arquivo theme.conf está no formato INI [1] (legível pelo módulo padrão Python configparser) e possui a seguinte estrutura:

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

[options]
variable = default value
  • A configuração inherit fornece o nome de um “tema base” ou None. O tema base será usado para localizar modelos ausentes (a maioria dos temas não precisará fornecer a maioria dos modelos se eles usarem o basic como tema base), suas opções serão herdadas e todos os seus arquivos estáticos também serão usados. Se você quiser também herdar a folha de estilo, inclua-a no CSS @import.

  • A configuração stylesheet fornece uma lista de nomes de arquivos CSS separados por vírgulas que serão referenciados no cabeçalho HTML. Você também pode usar a técnica CSS para incluir um do outro, ou usar um modelo HTML personalizado que adicione tags <link rel="stylesheet"> conforme necessário. Definir o valor de configuração html_style substituirá esta configuração.

  • A configuração pygments_style fornece o nome de um estilo Pygments a ser usado para destaque. Isso pode ser substituído pelo usuário no valor de configuração pygments_style.

  • The pygments_dark_style setting gives the name of a Pygments style to use for highlighting when the CSS media query (prefers-color-scheme: dark) evaluates to true. It is injected into the page using add_css_file().

  • A configuração sidebars fornece uma lista separada por vírgula de templates de barra lateral para a construção de barras laterais. Isso pode ser substituído pelo usuário no valor de configuração html_sidebars.

  • A seção options contém pares de nomes de variáveis ​​e valores padrão. Essas opções podem ser substituídas pelo usuário em html_theme_options e podem ser acessadas de todos os modelos como theme_<name>.

Adicionado na versão 1.7: configurações da barra lateral

Alterado na versão 5.1: The stylesheet setting accepts multiple CSS filenames

Convert theme.conf to theme.toml

INI-style theme configuration files (theme.conf) can be converted to TOML via a helper programme distributed with Sphinx. This is intended for one-time use, and may be removed without notice in a future version of Sphinx.

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

The required argument is a path to a directory containing a theme.conf file. The programme will write a theme.toml file in the same directory, and will not modify the original theme.conf file.

Adicionado na versão 7.3.

Distribuir seu tema como um pacote Python

As a way to distribute your theme, you can use a Python package. This makes it easier for users to set up your theme.

To distribute your theme as a Python package, please define an entry point called sphinx.html_themes in your pyproject.toml file, and write a setup() function to register your theme using the 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)

Se o seu pacote de temas contém dois ou mais temas, por favor, ligue add_html_theme() duas vezes ou mais.

Adicionado na versão 1.2: recurso entry_points de sphinx_themes.

Descontinuado desde a versão 1.6: sphinx_themes entry_points foi descontinuado.

Adicionado na versão 1.6: sphinx.html_themes recurso entry_points.

Styling with CSS

The stylesheets setting can be used to add custom CSS files to a theme.

Cuidado

The structure of the HTML elements and their classes are currently not a well-defined public API. Please infer them from inspecting the built HTML pages. While we cannot guarantee full stability, they tend to be fairly stable.

Styling search result entries by category

Adicionado na versão 8.0.

Nota

The CSS classes named below are generated by Sphinx’s standalone search code. If you are using a third-party search provider, such as ReadTheDocs, to provide search results, then the theming options available may vary.

The search result items have classes indicating the context in which the search term was found. You can use the CSS selectors:

  • ul.search li.kind-index: For results in an index, such as the glossary

  • ul.search li.kind-object: For results in source code, like Python function definitions

  • ul.search li.kind-title: For results found in section headings

  • ul.search li.kind-text: For results found anywhere else in the documentation text

As a base for inheritance by other themes, the basic theme is intentionally minimal and does not define CSS rules using these. Derived themes are encouraged to use these selectors as they see fit. For example, the following stylesheet adds contextual icons to the search result list:

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 */
}

Criando modelos

O guia para criação de modelos é útil se você quiser escrever seus próprios templates. O que é importante ter em mente é a ordem em que o Sphinx procura por modeleos:

  • Primeiro, nos diretórios do usuário templates_path.

  • Então, no tema selecionado.

  • Então, no tema básico, seu tema básico, etc.

When extending a template in the base theme with the same name, use the theme name as an explicit directory: {% extends "basic/layout.html" %}. From a user templates_path template, you can still use the “exclamation mark” syntax as described in the templating document.

Modelos Estáticos

Como as opções de tema são destinadas ao usuário para configurar um tema com mais facilidade, sem ter que escrever uma folha de estilo personalizada, é necessário ser capaz de criar templates de arquivos estáticos, bem como arquivos HTML. Portanto, o Sphinx suporta os chamados modelos estáticos, assim:

If the name of a file in the static/ directory of a theme (or in the user’s static path) ends with .jinja or _t, it will be processed by the template engine. The suffix will be removed from the final file name.

For example, a theme with a static/theme_styles.css.jinja file could use templating to put options into the stylesheet. When a documentation project is built with that theme, the output directory will contain a _static/theme_styles.css file where all template tags have been processed.

Alterado na versão 7.4:

The preferred suffix for static templates is now .jinja, in line with the Jinja project’s recommended file extension.

The _t file suffix for static templates is now considered ‘legacy’, and support may eventually be removed.

If a static template with either a _t suffix or a .jinja suffix is detected, it will be processed by the template engine, with the suffix removed from the final file name.

Use custom page metadata in HTML templates

Any key / value pairs in field lists that are placed before the page’s title will be available to the Jinja template when building the page within the meta attribute. For example, if a page had the following text before its first title:

:mykey: My value

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

Then it could be accessed within a Jinja template like so:

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

Note the check that meta is a dictionary (“mapping” in Jinja terminology) to ensure that using it in this way is valid.

Defining custom template functions

Sometimes it is useful to define your own function in Python that you wish to then use in a template. For example, if you’d like to insert a template value with logic that depends on the user’s configuration in the project, or if you’d like to include non-trivial checks and provide friendly error messages for incorrect configuration in the template.

To define your own template function, you’ll need to define two functions inside your module:

  • A page context event handler (or registration) function. This is connected to the Sphinx application via an event callback.

  • A template function that you will use in your Jinja template.

First, define the registration function, which accepts the arguments for html-page-context.

Within the registration function, define the template function that you’d like to use within Jinja. The template function should return a string or Python objects (lists, dictionaries) with strings inside that Jinja uses in the templating process

Nota

The template function will have access to all of the variables that are passed to the registration function.

At the end of the registration function, add the template function to the Sphinx application’s context with context['template_func'] = template_func.

Finally, in your extension’s setup() function, add your registration function as a callback for 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)

Now, you will have access to this function in jinja like so:

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

Add your own static files to the build assets

By default, Sphinx copies static files on the static/ directory of the template directory. However, if your package needs to place static files outside of the static/ directory for some reasons, you need to copy them to the _static/ directory of HTML outputs manually at the build via an event hook. Here is an example of code to accomplish this:

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)

Inject JavaScript based on user configuration

If your extension makes use of JavaScript, it can be useful to allow users to control its behavior using their Sphinx configuration. However, this can be difficult to do if your JavaScript comes in the form of a static library (which will not be built with Jinja).

There are two ways to inject variables into the JavaScript space based on user configuration.

First, you may append _t to the end of any static files included with your extension. This will cause Sphinx to process these files with the templating engine, allowing you to embed variables and control behavior.

For example, the following JavaScript structure:

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

Will result in the following static file placed in your HTML’s build output:

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

See Modelos Estáticos for more information.

Second, you may use the Sphinx.add_js_file() method without pointing it to a file. Normally, this method is used to insert a new JavaScript file into your site. However, if you do not pass a file path, but instead pass a string to the “body” argument, then this text will be inserted as JavaScript into your site’s head. This allows you to insert variables into your project’s JavaScript from Python.

For example, the following code will read in a user-configured value and then insert this value as a JavaScript variable, which your extension’s JavaScript code may use:

# 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)

As a result, in your theme you can use code that depends on the presence of this variable. Users can control the variable’s value by defining it in their conf.py file.