-
Notifications
You must be signed in to change notification settings - Fork 3
Description
Currently, our theming system only works for colors, using CSS light-dark(). But what about other content like images?
Currently there is no way to do this easily. Media queries do not work, since they do not reflect the current color-scheme, only the original user preference (see discussion).
It can be done using a custom --scheme variable that "tracks" the color-scheme (so must always be set at the same time as color-scheme), and then the CSS can adapt using a conditional. For example, using if(), or style container queries, or custom property hacks.
https://www.bram.us/2025/02/18/css-at-function-and-css-if/#custom-light-dark
There is discussion ongoing to allow getting the current color-scheme value through a color-scheme() condition inside an if() conditional: w3c/csswg-drafts#10577 (comment).
Codepen experiment:
https://codepen.io/maikelkrause/pen/ZYGVVGL?editors=1100
So the above is regarding what we can style in CSS itself, but about HTML content like <img> tags?
One idea is to use <picture> with media queries (for example: SO). However, this suffers from the same issue as above that prefers-color-scheme media queries do not reflect the current color-scheme.
If the image is SVG, then it could be done with an <svg><use/></svg> and then using CSS to style it, as done in this PR.
Another way is to use a CSS background image instead (but this has accessibility implications).
Lastly, one way to do this would be through JS using something like a ThemeProvider that would then have to match the current color-scheme somehow. (Idea: use a --scheme custom property and in JS get the computed value for it to determine the scheme of the current element?)
We can use something like the following to listen to events, where currentTheme should be the last known theme:
window.matchMedia(`prefers-color-scheme: ${currentTheme}`).addEventListener('change', handleChange, { once: true });
See this codepen for a similar example.