The Future of CSS: Easy Light-Dark Mode Color Switching with Light-Dark()
bram.us
bram.us
I'm not a fan of this. This solves one tiny aspect of the larger problem in a non-scalable way that will inevitably lead to bloat and inflexibility. It's a really a naive approach that hasn't taken into account design at scale, nor the future of where design is heading.
Typically when doing theming, you have two axes - a visual mode axis (i.e. light/dark/high contrast/colorblind modes/etc) and a theme axis (i.e. docs/sheets/slides, each with a different brand color). While this does solve an aspect of the visual mode axis, as soon as you add either a new theme or a visual accessibility mode, you'll be forced to refactor. I see that as codesmell.
I also don't think this helps drive a better future of theming support. If we think about the future of theming, what we see today is a convergence of design patterns. Nearly everyone is doing theming at scale in at least roughly the same way (a semantic token layer that points to different primitive colors depending on the theme), and the differences between implementations continues to diminish over time. The convergence of patterns is a good thing - it means more code can be shared.
If you wanted to actually solve theming, what you should work for is not a constrained helper function like light-dark(), but instead a shared token schema. Today nearly every company has their own token schema and different ways of naming things in the semantic token layer. If we had a shard language here, not only would it be trivial to add light/dark theming (just redefine a few variables that are already provided for you), code could be shared between sites and inherit the theming/branding.
[1] Most recently leading Figma's dark mode stream, and currently leading their variables feature work to enable others to easily do light/dark/etc. I've consulted with 50+ enterprise tier companies on their theming. Also contributed to the W3C design token proposal for theme/mode support: https://github.com/design-tokens/community-group/issues/210. Previously worked on Jira's dark mode + a few other projects.
I hate that we've picked off all the easy work on web design and now we're into problems we never even imagined 10 years ago, e.g. multiple visual modes, differing color spaces etc. This stuff is getting really, really hard to do well and do it right -- it is very easy to make things worse for a lot of users, rather than better.
For small projects that never need to "scale", this looks handy.
Nevertheless, it's a good idea to do so (though if a site honors `prefers-color-scheme` it should also have a setting so the user can choose to have that site not match their system's color scheme setting).
For the viewers at home:
:root {
color-scheme: light dark high-contrast;
}body {
background: scheme(light #eee, dark #333, high-contrast #fff);
}Could you explain or give an example of what this is?
Basically, when you think in purpose instead of colors.
Isn't that the idea behind https://open-props.style/ (and https://theme-ui.com/ in JS land)?
I think it's a great idea, but hampered by the lack of adoption incentives for the very people that need to adopt it for it to become successful (design system/component library authors). It introduces constraints, but the promised interoperability is not really beneficial to the people who need to work within those constraints.
> This solves one tiny aspect of the larger problem in a non-scalable way that will inevitably lead to bloat and inflexibility. It's a really a naive approach that hasn't taken into account design at scale, nor the future of where design is heading.
Note that `light-dark()` isn’t the end goal here. As discussed within the CSS WG, the end goal is to have a generic function `schemed-value()` to give you what you want.
I realize this wasn’t included in the post, so I’ve added a new section to the post with this information: https://www.bram.us/2023/10/09/the-future-of-css-easy-light-...
I hope this addresses your concern. If not, feel free to let me (or the CSS WG for that matter) know.
This is how standards get bloated.
You could deliver the same convenience in a way that’s set up to be repurposable (fullcolor /rgcolorblind) or extensible (light / grey / dark / …n) with as little difference as choosing a more mindful name.
You can already do this using the space toggle technique:
:root { --dark: ; }
@media (prefers-color-scheme: dark) { --light: ; --dark:initial; }
.example { color: var(--light, #000) var(--dark, #fff); }
I wonder if custom functions might ever make their way to css.
@media (prefers-color-scheme: dark) { :root { --light: ; --dark:initial; } }
Missed the selector.
Yes, `light-dark()` is very specific in what it can do … but it’s not the end goal. The end goal is to have a generic function – something like `schemed-value()` – that can respond to a plentitude of `color-scheme` values and return more than just `<color>` values.
Reality is, though, that browsers don’t have support for custom `color-scheme` values (it’s explicitly forbidden in the spec, for now) [^1] and that CSS parsers need to know ahead of time what they are about to parse [^2].
By narrowing things down in feature scope, you can use this convenience method now, instead of needing to wait a few months/years until the rest is figured out.
Once `schemed-value()` becomes a thing, `light-dark()` can become syntactic sugar for it:
``` light-dark(<color>, <color>); = schemed-value(light <color>, dark <color>); ```
[^1]: https://drafts.csswg.org/css-color-adjust/#color-scheme-prop... [^2]: https://www.w3.org/TR/css-syntax-3/#parse-grammar
Now it's "you can have any colour you want, as long as it's light or dark", and all of a sudden "dark mode" is heralded as something revolutionary and new.
CSS3 even deprecated the "system colors" feature that was meant to allow the same degree of UI customisation we had before for websites too.
It's nothing but a really sad regression in empowerment, the continuing trend of treating users like cattle.
Personally, I don’t mind the light-dark function although I don’t see much utility in it, since I use variables for this sort of thing.
Specific system color keywords were deprecated but the idea of system color keywords was not. They're essential for when `forced-colors` is active.
https://developer.mozilla.org/en-US/docs/Web/CSS/system-colo...
<meta name=color-scheme content="light dark">
then, in in-line CSS: @media (prefers-color-scheme:dark){body{background-color:#000;color:#eee}img{filter:brightness(.9)}}
I'm not seeing this new thing as a huge win so far.I have everything set to dark mode, but I wouldn't want the images altered. Unless these are just navigational images on your site and you don't have any photos?
* I just want everything to be dark on my screen because I like it.
* I am trying to use this device in a dark place.
* I want a dark, low-contrast background that doesn't compete with image colors.
The solutions to these three problems are all some kind of "dark mode" but each one needs a different solution. Sometimes one "dark mode" might work in conjunction with the user manually changing their brightness settings depending on the lighting in the environment, but not many people seem to design for that.
I wish they would just enable features that are already in the browser that they've not put live, like grid-template-rows: masonry. All three major engines have the damned thing in there but it's not in release branch.
I also check for CSS support in the browser using the "supports" feature and utilize the native support if it is enabled (e.g. Firefox behind a flag, and Safari behind a switch).
p.s. love your work
[^1]: https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3...
It’s nice to have the choice but I also wonder what else might have been done with all that UX/UI design and SWE time.
At one point I believe MacBook Pros were coming with default dark mode(or at least asking you which you prefer during startup).
My phone auto switches to dark preference based on time/environment.
Now, you don't want to be the ONLY product your user uses that blasts their eyeballs out because it doesn't respect system preferences.. Do you?
Also I m not a css expert but can't you also simplify it by using css variables so that you can further reduce the scope of change by having only the css variables that change value ? Your --primary-color-500 etc.
1. Less lines of code (seems like a good thing)
2. I will still need to use prefers-dark-mode for some of my changes.
Thus — the concept count is ratcheted up by 1 more thing, and no concept is taken away.
The “concept count” is ridiculously high already.
They’re spending money from an overdrawn account.
If you want to permanently increase the number of things that a bunch of people must learn, it has to have more value or power than this.
Can you detail what those would be? I’m curious to know :)
I may turn down the brightness on images, generally, in dark mode. (Using a filter).
And have some classes that mean “don’t alter the brightness of this image, in dark mode”
And there may be other images which I will invert the color of. For example any image that is basically black text on a white background — it’s better to invert it completely rather than just lower the brightness.
In the late 00s I wrote a frontend for a very popular open-source web project that many here would have encountered. Unlike many web projects these days, it is considered de rigueur for each instance to implement its own stylesheet. Most instances will also allow each user to select their own stylesheet.
This is trivial because the frontend was written HTML first. The HTML contains absolutely no hint at how the style should be. The navigation is just the navigation, the content is the content etc. The nav could be at the top, bottom, side, whatever you can come up. And people did all of them.
And, of course, some of those stylesheets were dark mode.
Print stylesheets were also common, which would hide all the web nav stuff when printing the document.
How did all the layers of crap added since then seem to forget this and make this quite simple concept difficult? You can't tell me it's difficult to build two stylesheets, one dark, one light, and have them both as options. And what about other accessibility options? Low contrast? High contrast? It's not just about dark and light...
I know that’s not how CSS works.
Unworkable in the sense that, for example, some elements are not physically positioned inside their container elements, and sometimes even in light dark mode you might use elements to create subtle layering etc, where you’d want the least contrast.
It wouldn’t be too difficult to write a gimmick webpage though, that implements the idea, to see what kind of fun would ensue.
I’ve got some sample code here that uses the little known but very powerful “tree Walker” to change elements 1 by 1.
https://til.secretgeek.net/css/replace_text_with_property_va...
And you can write javascript code that alters css variable values like this:
var root = document.documentElement; root.style.setProperty('--main-hue', 0);
I think the particular can of worms you’re suggesting could be very strange and interesting!
This method is pretty much ternary operator and it requires a browser support to be used, insanity.
Note that `light-dark()` is not the end station here, it’s a step towards a future function that (1) would be able to respond to any value for `color-scheme` and (2) can return any type of value.
I think this text is wrong. https://caniuse.com/?search=light-dark does not have an entry for this yet.
CanIUse has no entry for it, as this feature is brand new. The PR add the data (https://github.com/mdn/browser-compat-data/pull/20935) is still pending.
https://github.com/w3c/csswg-drafts/issues/7561#issuecomment...
color: media(min-width: 1001px, red, blue)
Easily toggling light/dark is part of the Web Preferences API feature, which is being prototyped in Chrome: https://chromestatus.com/feature/4631882616012800
So this is the first function which changes light gray with dark gray. And they call it "color". /s