You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Set CSS value in HTML to reflect current theme #192
See this page, where the anchor points to an SVG. If you ensure that there's no theme in local storage for this page, then if the browser settings are used to switch between dark and light modes (I'm using Firefox), the SVG is styled appropriately to display correctly. However, if I use the theme selector on the page to select dark mode when the browser is set to light mode, the SVG does not display correctly.
The reason is that I style for light mode and use a media query to override some styles, using @media (prefers-color-scheme: dark). However, when the theme selector is used to select dark mode, then some dark-mode CSS is pulled in using the activateTheme() JS function, but from what I can tell this leaves no trace in the markup that we're now in dark mode. If there were e.g. a dark-theme class added to the <body> tag when the page is in dark mode, then I could duplicate the styling using an appropriate selector. My complete styling of the SVG is:
If there is another approach I could use to achieve the desired result (proper styling of the SVG in all cases), please let me know. Otherwise, would you consider adding dark-theme class to the body or other container tag so that I could try and achieve the desired result? Or have I missed somewhere where such a class has been added?
I got this working by overwriting activateTheme with my own function, see here. The result can be previewed here. It would still be good to have the function of setting/unsetting body.{light,dark}-theme in this theme.
changed the title [-]SVG created to work in dark and light mode works as expected when using the browser to set the mode, but not when using the theme selector[/-][+]Set CSS value in HTML to reflect current theme[/+]on Jul 21, 2024
Yeah, https://peps.python.org/ has a data-colour_scheme attribute on the html element that changes between dark, light and auto based on the theme selection.
I'd welcome a PR to do something like this here too.
Do you want it to match the peps.python.org behaviour exactly? Or is what I've implemented (using the body tag, and the attribute has a -theme suffix) OK?
PyData's approach allows content to only care about the current display theme, with keeping relevant "what mode is selected" state separately, which would work better for the usecases like showing the dark mode SVG when content is dark.
The root problem is that inline SVG is styled via prefers-color-scheme, so when a user forces dark with the theme selector (while the OS is in light), there’s no DOM signal for CSS to hook onto. The clean fix is to expose the current selection on the root element and let authors target it. Use a single data attribute on :
data-theme: "light" | "dark" | "auto"
When mode = auto, remove the attribute so system media queries keep working. This mirrors PyData’s approach: keep “what the user picked” (auto/light/dark) separate from “how CSS applies.” With this contract, content authors can reliably style SVG and anything else.
CSS (solves the SVG case without breaking auto)
/* Base (light) */svg { background-color: transparent !important; }
line,polyline,polygon,rect { stroke:#000; fill: none; stroke-opacity:1; }
polygon.filled { fill:#f00; }
text { fill:#000; stroke: none; font-family: sans-serif; font-style: normal; font-weight: normal; text-anchor: start; }
/* Forced dark via selector */html[data-theme='dark'] line,html[data-theme='dark'] polyline,html[data-theme='dark'] polygon,html[data-theme='dark'] rect { stroke:#fff; }
html[data-theme='dark'] text { fill:#fff; }
/* Auto = no attribute; defer to OS */@media (prefers-color-scheme: dark) {
html:not([data-theme]) line,html:not([data-theme]) polyline,html:not([data-theme]) polygon,html:not([data-theme]) rect { stroke:#fff; }
html:not([data-theme]) text { fill:#fff; }
}
JS (tiny switcher contract the theme can call)
<script>
// Apply user selection: 'light' | 'dark' | 'auto'
function applyTheme(mode) {consthtml=document.documentElement;if(mode==='auto'){html.removeAttribute('data-theme');// let prefers-color-scheme rule} else {html.setAttribute('data-theme',mode);// force 'light' or 'dark'}
try {localStorage.setItem('theme',mode);} catch (e) {}}// Initialize on load from previous selection (default to auto)document.addEventListener('DOMContentLoaded',()=>{constsaved=(function(){try{returnlocalStorage.getItem('theme');}catch(e){returnnull;}})();applyTheme(saved||'auto');});
// Keep AUTO in sync with OS changes
const mql = window.matchMedia('(prefers-color-scheme: dark)');
mql.addEventListener('change', () =>{constmode=(function(){try{returnlocalStorage.getItem('theme')||'auto';}catch(e){return'auto';}})();if(mode==='auto')applyTheme('auto');});
// Optional: expose a stable hook if the theme already has a switcher
// window.activateTheme = applyTheme;
</script>
Optional no-FOUC pre-init (sets the attribute before first paint)
How this closes the issue: authors now have a deterministic selector (html[data-theme='dark']) for forced dark, and “auto” still honors prefers-color-scheme. Inline SVG and other embedded assets render correctly regardless of whether the user toggles via the site selector or the OS setting. Happy to open a PR wiring the attribute + storage and documenting the CSS contract above.
Activity
vsajip commentedon Jul 3, 2024
I got this working by overwriting
activateThemewith my own function, see here. The result can be previewed here. It would still be good to have the function of setting/unsettingbody.{light,dark}-themein this theme.[-]SVG created to work in dark and light mode works as expected when using the browser to set the mode, but not when using the theme selector[/-][+]Set CSS value in HTML to reflect current theme[/+]hugovk commentedon Jul 21, 2024
Yeah, https://peps.python.org/ has a
data-colour_schemeattribute on thehtmlelement that changes betweendark,lightandautobased on the theme selection.I'd welcome a PR to do something like this here too.
vsajip commentedon Jul 22, 2024
Do you want it to match the
peps.python.orgbehaviour exactly? Or is what I've implemented (using thebodytag, and the attribute has a-themesuffix) OK?hugovk commentedon Jul 22, 2024
We don't need to copy peps.python.org exactly.
Checking a couple of others:
Furo has a
<body data-theme="dark">which toggles the three states.PyData Sphinx Theme has the same thing, but it only togges light and dark. It also has a
data-modethat toggles the thee states.Hmm, shall we follow Furo?
pradyunsg commentedon Jul 22, 2024
I'd suggest following PyData Sphinx Theme honestly -- Furo's approach works because of the weird stacking it has due to the legacy of being a light-only theme that evolved a dark mode and requires... shenanigans (see https://github.com/pradyunsg/furo/blob/main/src/furo/assets/styles/base/_theme.sass which includes dark colors twice).
PyData's approach allows content to only care about the current display theme, with keeping relevant "what mode is selected" state separately, which would work better for the usecases like showing the dark mode SVG when content is dark.
ONKARBH commentedon Jan 21, 2025
Wulian233 commentedon Jan 21, 2025
ONKARBH commentedon Jan 21, 2025
sincehelloworld commentedon Nov 2, 2025
The root problem is that inline SVG is styled via prefers-color-scheme, so when a user forces dark with the theme selector (while the OS is in light), there’s no DOM signal for CSS to hook onto. The clean fix is to expose the current selection on the root element and let authors target it. Use a single data attribute on :
data-theme: "light" | "dark" | "auto"
When mode = auto, remove the attribute so system media queries keep working. This mirrors PyData’s approach: keep “what the user picked” (auto/light/dark) separate from “how CSS applies.” With this contract, content authors can reliably style SVG and anything else.
CSS (solves the SVG case without breaking auto)
JS (tiny switcher contract the theme can call)
Optional no-FOUC pre-init (sets the attribute before first paint)
How this closes the issue: authors now have a deterministic selector (html[data-theme='dark']) for forced dark, and “auto” still honors prefers-color-scheme. Inline SVG and other embedded assets render correctly regardless of whether the user toggles via the site selector or the OS setting. Happy to open a PR wiring the attribute + storage and documenting the CSS contract above.