3 ms·
> While this is really handy, it is a best practice to allow users to manually toggle the color-scheme as well. Some people prefer a dark system theme, but lig
by SquareWheel 1y ago
> While this is really handy, it is a best practice to allow users to manually toggle the color-scheme as well. Some people prefer a dark system theme, but light website themes, and vice-versa.
It can make sense for a theme selector that works on the server, since you can serve specific HTML when building the page. However, if using a JavaScript-based solution that fetches the theme preference from localStorage, I find this almost always results in a "flashbang" in dark mode, as the retrieval is slower than the first browser paint.
I've been implementing (and recommending) pure CSS-based theming to avoid this problem. Users seem much happier with them, and I haven't heard anybody ask for a theme switcher. We just respect their existing preference. However, I can see this being a problem if you offer multiple color schemes (beyond just light and dark).
I'd be curious to know if anybody has found a way to avoid this issue with JS switchers -- ideally without needing to delay the initial paint.
I do think an interesting approach would be a browser extension that lets you override the prefers-color-scheme property on a per-domain basis, similar to the toggle in dev tools.
- hucklebuckle 1y agoWhere can I learn more about CSS-based theming?
- bobbylarrybobby 1y agoYou might be surprised how little there is to know. There are basically three strategies: 1. set your light theme color variables in :root and your dark theme colors in `@media (prefers-color-scheme: dark) { :root { ... } }` 2. use the newish `--var: light-dark(light-value, dark-value)` syntax with `:root { color-scheme: light dark; }` 3. use a class on the body to determine whether to apply light or dark variables (can be used in combination with the above to default to user’s current theme while letting javascript toggle the theme by toggling the class)
- tom_alexander 1y agoIf you're just concerned about light vs dark, then this article (which was posted to HN) does an auto/light/dark toggle button without javascript, and it shows using CSS variables for your colors: https://lyra.horse/blog/2025/08/you-dont-need-js/ https://lyra.horse/blog/2025/08/you-dont-need-js/
- quest88 1y agoI’ve never tried it but the first thing that comes to mind is to use a service worker. The service worker would append a parameter to the initial request to indicate what theme is set in local storage. Then the initial response can use that as the default theme.
- marcosdumay 1y agoYou can always default to the user mode, and make a switcher that fetches another CSS file. That way you will have a flash, but if the user set dark mode on their browser/DE, they'll flash in dark, not light. Or, alternatively, you can always make it flash in dark. I never heard about anybody being annoyed by a dark flash.
- woodrowbarlow 1y agoa dark flash would definitely be annoying; it would feel like i'm using a first-gen e-reader.
- MarcelOlsz 1y agoThat's why I made my site all pixelated and bitmappy. The lack of performance is part of the aesthetic. Might even throw a dummy loading bar on it if I'm feeling extra cheeky.
- marcosdumay 1y agoOk, that comparison is ridiculous. A two monitor frames flash after the first load doesn't look at all like a first-gen e-reader.
- wry_discontent 1y agoimo it's best practice to not use light/dark themes. The site looks the way I want it to look. This isn't your site, it's mine.
- sionisrecur 1y agoWell if it's my site I want to give users choice between 2 styles. I remember Firefox used to have an option in the menu for selecting alternative stylesheets, multiple ones not just light and dark, I think it was a standard from CSS, but only Firefox had a way to select them through the UI, for other browsers you had to use Javascript to make a selector.
- reaperducer 1y agoimo it's best practice to not use light/dark themes. The site looks the way I want it to look. This isn't your site, it's mine. Thank you for illustrating the fact that the phrase "best practice" means nothing, and is little more than a synonym for "I heard this somewhere."
- ryandrake 1y agoSad that the state of affairs is that "offering a light and dark mode" is seen as a best practice for user choice in web styling. Oh, thank you, web developer, for letting me choose between two color schemes! Meanwhile, I can choose my desktop window colors, text colors, fonts, text size, down to the individual element, and have been able to do this since at least the 90s. If I want yellow comic sans on purple window backgrounds, I can have it. But not on a web page! How far we have regressed when it comes to user preferences and honoring them.
- im3w1l 1y agoIt's possible you just didn't look hard enough for how.
- hamburglar 1y agoYou seem to take offense at the idea that you have to read something that someone else designed. How do you cope with books, magazines, presentations, signs, menus in restaurants, etc? Calling this a “sad state of affairs” is pretty dramatic. You have to gaze upon things that aren’t in your preferred colors, oh my!
- array_key_first 1y agoIt's a sad state of affairs because it's a regression. This was trivial for websites 15 years ago, but due to increasing complexity, it's no longer feasible. We've put more and more styling type things in JS, which really undermines web as a platform. This is why CSS exists. This isn't some weirdo use case, this is THE use case. We're all losing the plot.
- mb2100 1y ago> if using a JavaScript-based solution that fetches the theme preference from localStorage, I find this almost always results in a "flashbang" in dark mode, as the retrieval is slower than the first browser paint. Not if you blockingly inline the three lines of JavaScript with a good old script tag right in the HTML.
- myfonj 1y ago> I do think an interesting approach would be a browser extension that lets you override the prefers-color-scheme property on a per-domain basis, similar to the toggle in dev tools. Presumably, most users wanting flashbang-less browsing experience use Dark Reader extension or similarly radical solutions. The sad truth is that the user preferences and per-site persistence for stuff like this should always have been browser's responsibility to begin with: just the same way like the font-size/page zoom already is, and likewise some (blatantly limited) security settings. (Bitterly) amusing fact is that there was (and still is) concept of "alternate stylesheets" from the beginning of CSS (still part of the spec [0], no support outside Gecko), that also fade into obsolescence for it's lack of persistence. So to this days, Firefox, for example, has View → Page Style menu, where user can choose alternate stylesheet but the choice is not preserved across navigations, so is pretty useless on its own. Similarly userstyles: specifications dictate there is like CSS origin level and how they should behave and that all "user agents" are supposed to give user a way to enter the cascade this way, but does not give any official way how to scope individual recipes to concrete origins. That's what the unofficial `@-moz-document` extension was that, and briefly had a chance to be formalised [1]. But I digress. (Likewise all the "European" cookies banners: tragic example of regulation applied on the wrong level. Instead of putting users in charge with help of their "user agents": implicitly blocking pretty much everything and using permissions system that actually would have a chance to be more than "pinky promise we will not track you if you don't click this toggle inside our banner". But I digress even more, sorry.) > I'd be curious to know if anybody has found a way to avoid this issue with JS switchers -- ideally without needing to delay the initial paint. At this point, when browsers do not support per-site user preference for that natively, pragmatic (most robust) way would be to respond with properly set HTML payload straight away. There is even specified HTTP header for this, so once adopted in browsers, we could even ditch HTTP cookies [2] for the persistence, but it seems quite demanding on the server (IIUC negotiating these "Client Hints" takes extra initial request round-trip). Pragmatically, I guess having early running JS in the HEAD that ensures the proper color-scheme is set on the root not and only proper stylesheets load should pretty much prevent most flashbangs, provided the relevant bit would arrive early enough from the server. I think there does not exist any good no-JS-no-Cookie (or any JS-less persistence) solution that supports navigations, sadly. [0] https://html.spec.whatwg.org/multipage/links.html#rel-alternate https://html.spec.whatwg.org/multipage/links.html#rel-altern... [1] https://www.w3.org/TR/2012/WD-css3-conditional-20121213/#changes https://www.w3.org/TR/2012/WD-css3-conditional-20121213/#cha... [2] https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Sec-CH-Prefers-Color-Scheme https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/...
- hypertexthero 1y agoHere’s what I use, with localStorage instead of cookies to remember user setting: https://hypertexthero.com/dark-mode-website-theme-switcher-localstorage/ https://hypertexthero.com/dark-mode-website-theme-switcher-l...
- SquareWheel 1y agoSorry to say, but your site does flashbang when navigating pages in dark mode. It would also be good if it inherited its initial state from the user preference, rather than requiring a manual adjustment.
- hypertexthero 1y agoThanks for the heads up. I never noticed before, but now I see it. Doesn’t bother me enough to change the technique at this time, but I’ve put it in the things to do list. I like the idea of having it automated by the system-set user preference in addition to having an option to set it manually with a link.
- tremon 1y ago> Your setting preference is saved with web browsers’ localStorage instead of cookies to help avoid needing “Accept Cookies” notes. I'm not aware of the specifics of regulations in other parts of the world, but this distinction is irrelevant for the EU ePrivacy directive: a) it was never about cookies only, and b) purely functional cookies that record user preferences do not need explicit consent. From [0]: > 34,35 Storage of information in the sense of Article 5(3) ePD refers to placing information on a physical electronic storage medium that is part of a user or subscriber’s terminal equipment [..] this includes making use of established protocols such as browser cookie storage as well as customized software, regardless of who created or installed the protocols or software on the terminal equipment. > 43 This might also be the case for web browsers that process information stored or generated information [sic] inside the device (such as cookies, local storage, WebSQL, or even information provided by the users themselves). The use of such information by an application would not be subject to Article 5(3) ePD as long as the information does not leave the device https://www.edpb.europa.eu/our-work-tools/documents/public-consultations/2023/guidelines-22023-technical-scope-art-53-eprivacy_en https://www.edpb.europa.eu/our-work-tools/documents/public-c...