Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow specifying multiple CSS files in themes #10465

Merged
merged 3 commits into from Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGES
Expand Up @@ -79,6 +79,9 @@ Deprecated
Features added
--------------

* #10444: html theme: Allow specifying multiple CSS files through the ``stylesheet``
setting in ``theme.conf`` or by setting ``html_style`` to an iterable of strings.

Bugs fixed
----------

Expand Down
11 changes: 7 additions & 4 deletions doc/development/theming.rst
Expand Up @@ -56,10 +56,10 @@ Python :mod:`ConfigParser` module) and has the following structure:
want to also inherit the stylesheet, include it via CSS' ``@import`` in your
own.

* The **stylesheet** setting gives the name of a CSS file which will be
referenced in the HTML header. If you need more than one CSS file, either
include one from the other via CSS' ``@import``, or use a custom HTML template
that adds ``<link rel="stylesheet">`` tags as necessary. Setting the
* The **stylesheet** setting gives a list of CSS filenames separated commas which
will be referenced in the HTML header. You can also use CSS' ``@import``
technique to include one from the other, or use a custom HTML template that
adds ``<link rel="stylesheet">`` tags as necessary. Setting the
:confval:`html_style` config value will override this setting.

* The **pygments_style** setting gives the name of a Pygments style to use for
Expand All @@ -82,6 +82,9 @@ Python :mod:`ConfigParser` module) and has the following structure:
.. versionadded:: 1.7
sidebar settings

.. versionchanged:: 5.1

The stylesheet setting accepts multiple CSS filenames

.. _distribute-your-theme:

Expand Down
18 changes: 18 additions & 0 deletions doc/templating.rst
Expand Up @@ -392,11 +392,29 @@ in the future.

.. versionadded:: 5.0.2

.. data:: styles

A list of the names of the main stylesheets as given by the theme or
:confval:`html_style`.

.. versionadded:: 5.1

.. data:: style

The name of the main stylesheet, as given by the theme or
:confval:`html_style`.

.. versionchanged:: 5.1

The theme or :confval:`html_style` are now able to specify multiple
stylesheets, the ``style`` key returns the last stylesheet when more than
one is specified.

.. deprecated:: 5.1

Use the :data:`styles` key instead, as there is no longer a single main
stylesheet. The ``style`` key will be removed in Sphinx 7.0.

.. data:: title

The title of the current document, as used in the ``<title>`` tag.
Expand Down
23 changes: 15 additions & 8 deletions sphinx/builders/html/__init__.py
Expand Up @@ -279,13 +279,16 @@ def _get_translations_js(self) -> str:
return jsfile
return None

def _get_style_filename(self) -> str:
if self.config.html_style is not None:
return self.config.html_style
def _get_style_filenames(self) -> Iterator[str]:
if isinstance(self.config.html_style, str):
yield self.config.html_style
elif self.config.html_style is not None:
yield from self.config.html_style
elif self.theme:
return self.theme.get_config('theme', 'stylesheet')
stylesheet = self.theme.get_config('theme', 'stylesheet')
yield from map(str.strip, stylesheet.split(','))
else:
return 'default.css'
yield 'default.css'

def get_theme_config(self) -> Tuple[str, Dict]:
return self.config.html_theme, self.config.html_theme_options
Expand Down Expand Up @@ -324,7 +327,9 @@ def init_highlighter(self) -> None:
def init_css_files(self) -> None:
self.css_files = []
self.add_css_file('pygments.css', priority=200)
self.add_css_file(self._get_style_filename(), priority=200)

for filename in self._get_style_filenames():
self.add_css_file(filename, priority=200)

for filename, attrs in self.app.registry.css_files:
self.add_css_file(filename, **attrs)
Expand Down Expand Up @@ -525,6 +530,7 @@ def prepare_writing(self, docnames: Set[str]) -> None:
# back up script_files and css_files to allow adding JS/CSS files to a specific page.
self._script_files = list(self.script_files)
self._css_files = list(self.css_files)
styles = list(self._get_style_filenames())

self.globalcontext = {
'embedded': self.embedded,
Expand Down Expand Up @@ -552,7 +558,8 @@ def prepare_writing(self, docnames: Set[str]) -> None:
'sphinx_version': __display_version__,
'sphinx_version_tuple': sphinx_version,
'docutils_version_info': docutils.__version_info__[:5],
'style': self._get_style_filename(),
'styles': styles,
'style': styles[-1], # xref RemovedInSphinx70Warning
'rellinks': rellinks,
'builder': self.name,
'parents': [],
Expand Down Expand Up @@ -1356,7 +1363,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
lambda self: _('%s %s documentation') % (self.project, self.release),
'html', [str])
app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
app.add_config_value('html_style', None, 'html', [str])
app.add_config_value('html_style', None, 'html', [list, str])
app.add_config_value('html_logo', None, 'html', [str])
app.add_config_value('html_favicon', None, 'html', [str])
app.add_config_value('html_css_files', [], 'html')
Expand Down
@@ -0,0 +1,3 @@
[theme]
inherit = basic
stylesheet = mytheme.css, extra.css
@@ -0,0 +1,2 @@
html_theme_path = ['_themes']
html_theme = 'mytheme'
@@ -0,0 +1,2 @@
test-build-html-theme-having-multiple-stylesheets
=================================================
9 changes: 9 additions & 0 deletions tests/test_build_html.py
Expand Up @@ -1782,3 +1782,12 @@ def test_theme_options_with_override(app, status, warning):
result = (app.outdir / '_static' / 'documentation_options.js').read_text(encoding='utf8')
assert 'NAVIGATION_WITH_KEYS: true' in result
assert 'ENABLE_SEARCH_SHORTCUTS: false' in result


@pytest.mark.sphinx('html', testroot='build-html-theme-having-multiple-stylesheets')
def test_theme_having_multiple_stylesheets(app):
app.build()
content = (app.outdir / 'index.html').read_text(encoding='utf-8')

assert '<link rel="stylesheet" type="text/css" href="_static/mytheme.css" />' in content
assert '<link rel="stylesheet" type="text/css" href="_static/extra.css" />' in content