Skip to content

Commit e7fc03b

Browse files
tk0miyaAA-Turner
andauthored
Allow specifying multiple CSS files in themes (#10465)
Co-authored-by: Adam Turner <[email protected]>
1 parent 8f893a6 commit e7fc03b

File tree

10 files changed

+59
-12
lines changed

10 files changed

+59
-12
lines changed

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ Deprecated
7979
Features added
8080
--------------
8181

82+
* #10444: html theme: Allow specifying multiple CSS files through the ``stylesheet``
83+
setting in ``theme.conf`` or by setting ``html_style`` to an iterable of strings.
84+
8285
Bugs fixed
8386
----------
8487

doc/development/theming.rst

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,10 @@ Python :mod:`ConfigParser` module) and has the following structure:
5656
want to also inherit the stylesheet, include it via CSS' ``@import`` in your
5757
own.
5858

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

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

85+
.. versionchanged:: 5.1
86+
87+
The stylesheet setting accepts multiple CSS filenames
8588

8689
.. _distribute-your-theme:
8790

doc/templating.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,11 +392,29 @@ in the future.
392392

393393
.. versionadded:: 5.0.2
394394

395+
.. data:: styles
396+
397+
A list of the names of the main stylesheets as given by the theme or
398+
:confval:`html_style`.
399+
400+
.. versionadded:: 5.1
401+
395402
.. data:: style
396403

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

407+
.. versionchanged:: 5.1
408+
409+
The theme or :confval:`html_style` are now able to specify multiple
410+
stylesheets, the ``style`` key returns the last stylesheet when more than
411+
one is specified.
412+
413+
.. deprecated:: 5.1
414+
415+
Use the :data:`styles` key instead, as there is no longer a single main
416+
stylesheet. The ``style`` key will be removed in Sphinx 7.0.
417+
400418
.. data:: title
401419

402420
The title of the current document, as used in the ``<title>`` tag.

sphinx/builders/html/__init__.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -279,13 +279,16 @@ def _get_translations_js(self) -> str:
279279
return jsfile
280280
return None
281281

282-
def _get_style_filename(self) -> str:
283-
if self.config.html_style is not None:
284-
return self.config.html_style
282+
def _get_style_filenames(self) -> Iterator[str]:
283+
if isinstance(self.config.html_style, str):
284+
yield self.config.html_style
285+
elif self.config.html_style is not None:
286+
yield from self.config.html_style
285287
elif self.theme:
286-
return self.theme.get_config('theme', 'stylesheet')
288+
stylesheet = self.theme.get_config('theme', 'stylesheet')
289+
yield from map(str.strip, stylesheet.split(','))
287290
else:
288-
return 'default.css'
291+
yield 'default.css'
289292

290293
def get_theme_config(self) -> Tuple[str, Dict]:
291294
return self.config.html_theme, self.config.html_theme_options
@@ -324,7 +327,9 @@ def init_highlighter(self) -> None:
324327
def init_css_files(self) -> None:
325328
self.css_files = []
326329
self.add_css_file('pygments.css', priority=200)
327-
self.add_css_file(self._get_style_filename(), priority=200)
330+
331+
for filename in self._get_style_filenames():
332+
self.add_css_file(filename, priority=200)
328333

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

529535
self.globalcontext = {
530536
'embedded': self.embedded,
@@ -552,7 +558,8 @@ def prepare_writing(self, docnames: Set[str]) -> None:
552558
'sphinx_version': __display_version__,
553559
'sphinx_version_tuple': sphinx_version,
554560
'docutils_version_info': docutils.__version_info__[:5],
555-
'style': self._get_style_filename(),
561+
'styles': styles,
562+
'style': styles[-1], # xref RemovedInSphinx70Warning
556563
'rellinks': rellinks,
557564
'builder': self.name,
558565
'parents': [],
@@ -1356,7 +1363,7 @@ def setup(app: Sphinx) -> Dict[str, Any]:
13561363
lambda self: _('%s %s documentation') % (self.project, self.release),
13571364
'html', [str])
13581365
app.add_config_value('html_short_title', lambda self: self.html_title, 'html')
1359-
app.add_config_value('html_style', None, 'html', [str])
1366+
app.add_config_value('html_style', None, 'html', [list, str])
13601367
app.add_config_value('html_logo', None, 'html', [str])
13611368
app.add_config_value('html_favicon', None, 'html', [str])
13621369
app.add_config_value('html_css_files', [], 'html')

tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/extra.css

Whitespace-only changes.

tests/roots/test-build-html-theme-having-multiple-stylesheets/_themes/mytheme/_static/mytheme.css

Whitespace-only changes.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[theme]
2+
inherit = basic
3+
stylesheet = mytheme.css, extra.css
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
html_theme_path = ['_themes']
2+
html_theme = 'mytheme'
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
test-build-html-theme-having-multiple-stylesheets
2+
=================================================

tests/test_build_html.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,3 +1782,12 @@ def test_theme_options_with_override(app, status, warning):
17821782
result = (app.outdir / '_static' / 'documentation_options.js').read_text(encoding='utf8')
17831783
assert 'NAVIGATION_WITH_KEYS: true' in result
17841784
assert 'ENABLE_SEARCH_SHORTCUTS: false' in result
1785+
1786+
1787+
@pytest.mark.sphinx('html', testroot='build-html-theme-having-multiple-stylesheets')
1788+
def test_theme_having_multiple_stylesheets(app):
1789+
app.build()
1790+
content = (app.outdir / 'index.html').read_text(encoding='utf-8')
1791+
1792+
assert '<link rel="stylesheet" type="text/css" href="_static/mytheme.css" />' in content
1793+
assert '<link rel="stylesheet" type="text/css" href="_static/extra.css" />' in content

0 commit comments

Comments
 (0)