From 02f5fda955d67d5a76dcc60f57a1bfbe40e4df2c Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 27 Jul 2026 14:42:57 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Theme-proof=20the=20stylesheet?= =?UTF-8?q?=20cascade=20(fix=20Furo=20render-pane=20padding)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Furo links furo-extensions.css AFTER extension html_css_files, so its [role=main] .container reset (0,2,0) won the specificity tie against .syntax-example > .syntax-example-render (0,2,0) and zeroed the render pane's horizontal padding — the old cascade comment's assumption that extension CSS loads last was wrong. Stop relying on stylesheet order entirely: - render pane: also match .syntax-example-render.container (0,3,0), using the container class docutils emits, beating theme resets at any load order (unqualified selector kept for writers without the class) - outer frame: .syntax-example.container neutralizes Bootstrap-style .container layout (width cap, centring margins, gutter padding) that other theme families attach to the docutils class - rewrite the cascade note to document the specificity strategy Verified in headless Chromium against a Furo build: render-pane computed padding-left 0px before, 12.8px (.8rem) after; frame geometry unchanged. 17/17 tests pass. --- CHANGELOG.md | 10 ++++ .../static/sphinx-syntax-example.css | 46 ++++++++++++------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42db461..ad113fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## Unreleased + +### 🐛 Fixes + +- The stylesheet no longer relies on load order to win ties against theme + rules: the render pane's padding now out-specifies theme `.container` + resets (fixing the missing horizontal padding under Furo, which links its + `furo-extensions.css` *after* extension stylesheets), and Bootstrap-style + `.container` layout is neutralized on the outer frame. + ## v0.1.0 (2026-07-27) Initial release. diff --git a/src/sphinx_syntax_example/static/sphinx-syntax-example.css b/src/sphinx_syntax_example/static/sphinx-syntax-example.css index 1da4025..d56a106 100644 --- a/src/sphinx_syntax_example/static/sphinx-syntax-example.css +++ b/src/sphinx_syntax_example/static/sphinx-syntax-example.css @@ -13,22 +13,26 @@ CASCADE NOTE — the child-combinator selectors below are DELIBERATE, not stylistic; do not "simplify" them to a single class. docutils tags the render pane and the outer box with the `container` class, and Sphinx tags the source - pane `highlight-`, so some themes' own rules match our elements and - (being more specific than a lone class) would otherwise win. The known - offenders, from Furo's bundled `furo-extensions.css` / theme CSS, are: + pane `highlight-`, so themes' own rules match our elements. Where that + happens, the rules below beat the theme on SPECIFICITY (qualifying with the + docutils-emitted `container` class) and never rely on stylesheet order: + load order is theme policy, not ours — Furo, for one, links its + `furo-extensions.css` (whose `[role=main] .container`, 0,2,0, zeroes + horizontal padding) AFTER extension `html_css_files`, so an + equal-specificity "tie" resolves to the theme, not to us. - - `[role=main] .container` (specificity 0,2,0) zeroes `padding-left/right` — - this is what blanks the render pane's horizontal padding. - `.syntax-example > .syntax-example-render` (0,2,0) ties it, and Sphinx loads - extension `html_css_files` AFTER the theme CSS, so the tie resolves to us. - - `div[class*=" highlight-"]` (0,1,1) sets `margin: 1em 0` on the source pane; - `.syntax-example > .syntax-example-source` (0,2,0) beats it outright. - - The outer `.syntax-example` (0,1,0) is intentionally left low: it sets no - horizontal padding, so a theme zeroing that padding (and setting - `max-width: none`) is a harmless no-op on the frame. The rubric is a `

`, - not a `.container`, so only docutils' `p.rubric` (0,1,1) competes and - `.syntax-example > .rubric` (0,2,0) wins. */ + - render pane: theme `.container` padding resets (Furo) lose to + `.syntax-example > .syntax-example-render.container` (0,3,0) at any load + order. The unqualified selector is kept alongside for a writer that emits + no `container` class — exactly the case where no theme `.container` rule + can interfere either. + - outer frame: Bootstrap-family themes give `.container` a width cap, + auto-centring margins and gutter padding; `.syntax-example.container` + (0,2,0) restores the frame's own geometry above their (0,1,0). + - source pane: `div[class*=" highlight-"]` (0,1,1) margins lose to + `.syntax-example > .syntax-example-source` (0,2,0) outright. + - rubric: a `

`, not a `.container`, so only docutils' `p.rubric` (0,1,1) + competes and `.syntax-example > .rubric` (0,2,0) wins. */ .syntax-example { /* Package-owned properties: theme variable first, light default second. */ @@ -42,6 +46,15 @@ overflow: hidden; } +.syntax-example.container { + /* Undo Bootstrap-style `.container` layout (width cap, auto-centring, + gutter padding) that some themes attach to the docutils class. */ + width: auto; + max-width: none; + margin: 1rem 0; + padding: 0; +} + @media (prefers-color-scheme: dark) { /* Only the fallback defaults change; a theme that defines the `--color-*` variables still wins, so this affects non-Furo dark themes only. */ @@ -68,7 +81,8 @@ border-bottom: 1px solid var(--syntax-example-border); } -.syntax-example > .syntax-example-render { +.syntax-example > .syntax-example-render, +.syntax-example > .syntax-example-render.container { padding: .3rem .8rem; }