Customizing the theme#

In addition to the configuration options detailed at Configuration, it is also possible to customize the HTML layout and CSS style of the theme.

Danger

This theme is still under active development, and we make no promises about the stability of any specific HTML structure, CSS variables, etc. Make these customizations at your own risk, and pin versions if you’re worried about breaking changes!

Custom CSS Stylesheets#

You may customize the theme’s CSS by creating a custom stylesheet that Sphinx uses to build your site. Any rules in this style-sheet will over-ride the default theme rules.

To add a custom stylesheet, follow these steps:

  1. Create a CSS stylesheet in _static/css/custom.css, and add the CSS rules you wish.

  2. Attach the stylesheet to your Sphinx build. Add the following to conf.py

    html_static_path = ['_static']
    
    html_css_files = [
        'css/custom.css',
    ]
    

When you build your documentation, this stylesheet should now be activated.

Manage light and dark themes#

You can change the major background / foreground colors of this theme according to “dark” and “light” modes. These are controlled by a button in the navigation header, with the following options:

  • A light theme with a bright background and dark text / UI elements

  • A dark theme with a dark background and light text / UI elements

  • auto: the documentation theme will follow the system default that you have set

Customize the CSS of light and dark themes#

Danger

Theming is still a beta feature so the variables related to the theme switch are likely to change in the future. No backward compatibily is guaranteed when customization is done.

To customize the CSS of page elements in a theme-dependent manner, use the html[data-theme='<THEME>'] CSS selector. For example to define a different background color for both the light and dark themes:

/* anything related to the light theme */
html[data-theme="light"] {

    /* whatever you want to change */
    background: white;
}

/* anything related to the dark theme */
html[data-theme="dark"] {

    /* whatever you want to change */
    background: black;
}

A complete list of the used colors for this theme can be found in the pydata default css colors file.

Use theme-dependent content#

It is possible to use different content for light and dark mode, so that the content only shows up when a particular theme is active. This is useful if your content depends on the theme’s style, such as a PNG image with a light or a dark background.

There are two CSS helper classes to specify items on the page as theme-specific. These are:

  • only-dark: Only display an element when the dark theme is active.

  • only-light Only display an element when the light theme is active.

For example, the following page content defines two images, each of which uses a different one of the classes above. Change the theme and a new image should be displayed.

.. image:: https://source.unsplash.com/200x200/daily?cute+cat
    :class: only-dark

.. image:: https://source.unsplash.com/200x200/daily?cute+dog
    :class: only-light
https://source.unsplash.com/200x200/daily?cute+cat https://source.unsplash.com/200x200/daily?cute+dog

Define custom JavaScript to react to theme changes#

You can define a JavaScript event hook that will run your code any time the theme changes. This is useful if you need to change elements of your page that cannot be defined by CSS rules. For example, to change an image source (e.g., logo) whenever the data-theme changes, a snippet like this can be used:

.. raw:: html

  <script type="text/javascript">
    var observer = new MutationObserver(function(mutations) {
      const dark = document.documentElement.dataset.theme == 'dark';
      document.getElementsByClassName('mainlogo')[0].src = dark ? '_static/my_logo_dark.svg' : "_static/my_logo_light.svg";
    })
    observer.observe(document.documentElement, {attributes: true, attributeFilter: ['data-theme']});
  </script>
  <link rel="preload" href="_static/my_logo_dark.svg" as="image">

.. image:: _static/my_logo_light.svg
   :alt: My Logo
   :class: logo, mainlogo
   :align: center

The JavaScript reacts to data-theme changes to alter img, and the link is used to preload the dark image. See the MutationObserver documentation for more information.

CSS Theme variables#

This theme defines several CSS variables that can be used to quickly control behavior and display across your documentation.

These are based on top of the basic Bootstrap CSS variables extended with some theme specific variables.

base variables#

In order to change a variable, follow these steps:

  1. Add a custom CSS stylesheet. This is where we’ll configure the variables.

  2. Underneath a :root section, add the variables you wish to update. For example, to update the base font size, you might add this to custom.css:

    :root {
        --pst-font-size-base: 17px;
    }
    

Important

Note that these are CSS variables and not SASS variables. The theme is defined with CSS variables, not SASS variables! Refer to the previous section if you desire a different behavior between the light and dark theme.

For a complete list of the theme variables that you may override, see the theme variables defaults CSS file:

:root {
  /*****************************************************************************
  * Overall Layout Variables
  */
  --pst-header-height: 60px;
}
:root {
  /*****************************************************************************
  * Font features used in this theme
  */

  // base font size - applied at body/html level
  --pst-font-size-base: 15px;

  // heading font sizes
  --pst-font-size-h1: 36px;
  --pst-font-size-h2: 32px;
  --pst-font-size-h3: 26px;
  --pst-font-size-h4: 21px;
  --pst-font-size-h5: 18px;
  --pst-font-size-h6: 16px;

  // smaller then heading font sizes
  --pst-font-size-milli: 12px;

  // primary sidebar management
  --pst-sidebar-primary-font-size: 0.9em;
  --pst-sidebar-primary-caption-font-size: 0.9em;

  // Font family
  // These are adapted from https://systemfontstack.com/ */
  --pst-font-family-base-system: -apple-system, BlinkMacSystemFont, Segoe UI,
    "Helvetica Neue", Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji,
    Segoe UI Symbol;
  --pst-font-family-monospace-system: "SFMono-Regular", Menlo, Consolas, Monaco,
    Liberation Mono, Lucida Console, monospace;

  --pst-font-family-base: var(--pst-font-family-base-system);
  --pst-font-family-heading: var(--pst-font-family-base-system);
  --pst-font-family-monospace: var(--pst-font-family-monospace-system);
}
:root {
  /*****************************************************************************
  * Icon
  */

  // font awesome icons
  --pst-icon-check-circle: "\f058"; // fas fa-check-circle
  --pst-icon-info-circle: "\f05a"; // fas fa-info-circle
  --pst-icon-exclamation-triangle: "\f071"; // fas fa-exclamation-triangle
  --pst-icon-exclamation-circle: "\f06a"; // fas fa-exclamation-circle
  --pst-icon-times-circle: "\f057"; // fas fa-times-circle
  --pst-icon-lightbulb: "\f0eb"; // fas fa-lightbulb
}
:root {
  /*****************************************************************************
  * Admonitions
  **/

  --pst-icon-admonition-default: var(--pst-icon-info-circle);
  --pst-icon-admonition-note: var(--pst-icon-info-circle);
  --pst-icon-admonition-attention: var(--pst-icon-exclamation-circle);
  --pst-icon-admonition-caution: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-warning: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-danger: var(--pst-icon-exclamation-triangle);
  --pst-icon-admonition-error: var(--pst-icon-times-circle);
  --pst-icon-admonition-hint: var(--pst-icon-lightbulb);
  --pst-icon-admonition-tip: var(--pst-icon-lightbulb);
  --pst-icon-admonition-important: var(--pst-icon-exclamation-circle);
}
:root {
  /*****************************************************************************
  * versionmodified
  **/

  --pst-icon-versionmodified-default: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-added: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-changed: var(--pst-icon-exclamation-circle);
  --pst-icon-versionmodified-deprecated: var(--pst-icon-exclamation-circle);
}

Color variables#

There are two special color variables for primary and secondary theme colors (--pst-color-primary and --pst-color-secondary, respectively). These are meant to complement one another visually across the theme, if you modify these, choose colors that look good when paired with one another.

There are also several other color variables that control color for admonitions, links, menu items, etc.

Each color variable has two values, one corresponding to the “light” and one for the “dark” theme. These are used throughout many of the theme elements to define text color, background color, etc.

You can control the colors used for these variables for each theme by adding a custom CSS stylesheet and adding a structure like so:

html[data-theme="light"] {
    --pst-color-primary: black;
}

html[data-theme="dark"] {
    --pst-color-primary: white;
}

For a complete list of the theme colors that you may override, see the color variables defaults CSS file:

/*******************************************************************************
* light theme
*
* all the variables used for light theme coloring
*/
html[data-theme="light"] {
  /*****************************************************************************
  * main colors
  */
  --pst-color-primary: rgb(69 157 185);
  --pst-color-secondary: rgb(238 144 64);
  --pst-color-success: rgb(40, 167, 69);
  --pst-color-info: var(--pst-color-primary);
  --pst-color-warning: var(--pst-color-secondary);
  --pst-color-danger: rgb(220, 53, 69);
  --pst-color-text-base: rgb(51, 51, 51);
  --pst-color-text-muted: rgb(77, 77, 77);
  --pst-color-border: rgb(201, 201, 201);
  --pst-color-shadow: rgb(216, 216, 216);

  /*****************************************************************************
  * depth colors
  *
  * background: the more in depth color
  * on-background: the object directly set on the background, use of shadows in light theme
  * surface: object set on the background (without shadows)
  * on_surface: object set on surface object (without shadows)
  */
  --pst-color-background: rgb(255, 255, 255);
  --pst-color-on-background: rgb(255, 255, 255);
  --pst-color-surface: rgb(240, 240, 240);
  --pst-color-on-surface: rgb(255, 255, 238);

  /*****************************************************************************
  * extentions
  */

  --pst-color-panel-background: var(--pst-color-background);

  /*****************************************************************************
  * layout
  */

  // links
  --pst-color-link: var(--pst-color-primary);
  --pst-color-link-hover: var(--pst-color-secondary);

  // inline code
  --pst-color-inline-code: rgb(232, 62, 140);

  // targeted content
  --pst-color-target: rgb(251, 229, 78);

  // hide any content that should not be displayed in the light theme
  .only-dark {
    display: none !important;
  }
}

/*******************************************************************************
* dark theme
*
* all the variables used for dark theme coloring
*/
html[data-theme="dark"] {
  /*****************************************************************************
  * main colors
  */
  --pst-color-primary: rgb(69 157 185);
  --pst-color-secondary: rgb(238 144 64);
  --pst-color-success: rgb(72, 135, 87);
  --pst-color-info: var(--pst-color-primary);
  --pst-color-warning: var(--pst-color-secondary);
  --pst-color-danger: rgb(203, 70, 83);
  --pst-color-text-base: rgb(201, 209, 217);
  --pst-color-text-muted: rgb(192, 192, 192);
  --pst-color-border: rgb(192, 192, 192);
  --pst-color-shadow: var(--pst-color-background);

  /*****************************************************************************
  * depth colors
  *
  * background: the more in depth color
  * on-background: the object directly set on the background, use of a light grey in dark theme
  * surface: object set on the background (without shadows)
  * on_surface: object set on surface object (without shadows)
  */
  --pst-color-background: rgb(18, 18, 18);
  --pst-color-on-background: rgb(30, 30, 30);
  --pst-color-surface: rgb(41, 41, 41);
  --pst-color-on-surface: rgb(55, 55, 55);

  /*****************************************************************************
  * extentions
  */

  --pst-color-panel-background: var(--pst-color-background-up);

  /*****************************************************************************
  * layout
  */

  // links
  --pst-color-link: var(--pst-color-primary);
  --pst-color-link-hover: var(--pst-color-secondary);

  // inline code
  --pst-color-inline-code: rgb(221, 158, 194);

  // targeted content
  --pst-color-target: rgb(71, 39, 0);

  // hide any content that should not be displayed in the dark theme
  .only-light {
    display: none !important;
  }

  // specific brightness applied on images
  img {
    filter: brightness(0.8) contrast(1.2);
  }
}

Replacing/Removing Fonts#

The theme includes the FontAwesome 5 Free icon font (the .fa, .far, .fas styles, which are used for icon links and admonitions). This is the only vendored font, and otherwise the theme by default relies on available system fonts for normal body text and headers.

Attention

Previously-included fonts like Lato have been removed, preferring the most common default system fonts of the reader’s computer. This provides both better performance, and better script/glyph coverage than custom fonts, and is recommended in most cases.

The default body and header fonts can be changed as follows:

  • Using Custom CSS Stylesheets, you can specify which fonts to use for body, header and monospace text. For example, the following can be added to a custom css file:

    :root {
        --pst-font-family-base: Verdana, var(--pst-font-family-base-system);
        --pst-font-family-heading: Cambria, Georgia, Times, var(--pst-font-family-base-system);
        --pst-font-family-monospace: Courier, var(--pst-font-family-monospace-system);
    }
    

    The -system variables are available to use as fallback to the default fonts.

  • If the font you want to specify in the section above is not generally available by default, you will additionally need to ensure the font is loaded. For example, you could download and vendor the font in the _static directory of your Sphinx site, and then update the base template to load the font resources:

    • Configure the template_path in your conf.py

    • Create a custom layout.html Jinja2 template which overloads the fonts block (example for loading the Lato font that is included in the _static/vendor directory):

      {% extends "pydata_sphinx_theme/layout.html" %}
      
      {% block fonts %}
        <!-- add `style` or `link` tags with your CSS `@font-face` declarations here -->
        <!-- ... and optionally preload the `woff2` for snappier page loads -->
        <link rel="stylesheet" href="{{ pathto('_static/vendor/lato_latin-ext/1.44.1/index.css', 1) }}">
      
      {% endblock %}
      

      To reduce the Flash of Unstyled Content, you may wish to explore various options for preloading content, specifically the binary font files. This ensure the files will be loaded before waiting for the CSS to be parsed, but should be used with care.