Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
CSS Only dark mode without JS (simondalvai.com)
33 points by dulvui on June 24, 2023 | hide | past | favorite | 53 comments


I am not sure why this qualifies as a front page article. To achieve color schemes in CSS only follow these steps.

1) Remove ALL color information from your CSS files and relocate that into a new CSS file only for color information. That is your default color scheme.

2) In that color scheme file prefix each rule with the same class name, possibly colorDefault.

3) Create a second color only CSS file with dark colors. This is your dark color scheme. Change the colorDefault class name to something else, possibly: colorDark.

4) Include those color files in your site using either media queries from the primary CSS or link tags in the HTML.

5) Finally add class name colorDefault to your HTML body tag. Use JavaScript to change that one class name as the user selects a different color scheme on user interaction.

Here is an example:

https://github.com/prettydiff/share-file-systems/tree/master...


What I did:

- used css-vars for all colors throught code

- named those vars semantically after what their layout role is (e.g. --table-border-color, --link-color, ...)

- create 2 media-queries (or one default definition and one queried overwrite) with @media (prefers-color-scheme: light) at the root, in which I assigned those layout-role-named colors their dark-/light mode specific color (--link-color: #aa1100)

- turned those colors that I assign into css-vars themselves, named after ... well, their color (e.g. --link-color: var(--brandname-red-light), ...)

Works remarkebly well (almost didn't need another prefers-color-scheme* anywhere else). But in the end JS was needed to make it toggable and persistable within localstorage. But the only neccessary change in CSS was to turn the refers-color-scheme*-media queries into classnames.


“CSS only” and “Use JavaScript to change” seems to be contradictory.


The difference in color schemes is one class name on one tag. You can also make that change on the back end or anywhere else.


Your solution is more complicated, and requires JS to run. One in link, is done purely with CSS as it should be.


No, it's not as it should be - there should always be a toggle. You should respect the user setting as the default, but please, always include a toggle.


It should not be the website's role to provide user controls over this. Having a website require JS to be acceptable is not acceptable. It's possible to use CSS only to check a input element's state, which feels like a workaround. But even then having each site provide its own way to toggle schemes in a pain. Searching for that toggle just adds to the list of settings we need to discover and configure for every notable website we visit. (Is it in the footer? Settings? User menu? Does it even exist or did I miss it?).

The browser should allow per-site toggles for prefers-color-scheme. Just like how (some?) browsers ship with page style selectors using CSS alternate tags. e.g. on Firefox Alt > View > Page Styles.

https://developer.mozilla.org/en-US/docs/Web/CSS/Alternative...


I would like proper browser toggles. But they are not here, and as long as they are not here, you should always include a toggle. Why is it not acceptable to require JS to be acceptable? You can always provide a pure CSS fallback for those who make the deliberately make the tradeoff of disabling JS. But don't force everybody else to change their whole system color preference just for your website when three lines of JS allow you to create a perfectly integrated toggle.


I think saying "everybody else" is an exaggeration. It's a minority (possibly a major on HN, including me) who tweak colour schemes. Just like how people rarely used alternate stylesheets. And why it took so long to even get "prefers-color-scheme".

Colour preferences are also not black and white, literally. There is a spectrum. Some websites' schemes are too dark or too bright. It's why sites like GitHub provide more than just two options. And why Dark Reader has sliders. In that sense, alternative stylesheets are a much better existing browser-level solution when user intervention is involved. After all, most applications provide a list of color schemes to choose from like in IDEs, terminals, word processors and so on.

The only reason I personally switch from dark to light mode on some websites is because their dark mode isn't what I want and I'd rather put up with the light mode. It's not a preference, just a compromise between two extremes.

Having an absolute stance on this is untenable since it's a complex situation depending on the site's audience, capacity, goal and so on. Let website owners decide, so they can focus on what's important to their audience.

For example, for my blog, I suggest people use the RSS feed or Reader Mode to adjust colours and font sizes to their liking. I'm not going to spend time tweaking two colour schemes for some unknown audience, which would just put me off writing and publishing.


> I think saying "everybody else" is an exaggeration. It's a minority (possibly a major on HN, including me) who tweak colour schemes.

Doesn't matter. "Everybody else" is the literal amount of people who have to change their system color scheme to change the color scheme of your website because you don't want to implement a toggle. You can't argue around that, it is per definition correct. Anyone who has JS enabled could use a toggle, but you don't implement it, so they have to change their system color scheme.

> Colour preferences are also not black and white, literally. There is a spectrum.

And because it's not black and white you force people to change their system color scheme to change your websites color scheme? This is a non-sequitur.

> The only reason I personally switch from dark to light mode on some websites is because their dark mode isn't what I want and I'd rather put up with the light mode. It's not a preference, just a compromise between two extremes.

And because of this you want to make it harder to change color schemes? How does that make any sense?

> Having an absolute stance on this is untenable since it's a complex situation depending on the site's audience, capacity, goal and so on. Let website owners decide, so they can focus on what's important to their audience.

No. Let the website owners give their users options. It's not that hard.

> For example, for my blog, I suggest people use the RSS feed or Reader Mode to adjust colours and font sizes to their liking. I'm not going to spend time tweaking two colour schemes for some unknown audience, which would just put me off writing and publishing.

And that's totally fine! If you don't have separate color schemes, it would make no sense to include a toggle. But if you have separate color schemes, add a toggle.


> No. Let the website owners give their users options. It's not that hard.

If it's not hard, shouldn't that ideal be towards the handful of browser vendors rather than the thousands/millions of website owners? I agree, if you're going out of your way to provide different stylesheets, provide a toggle, otherwise it's kind of a wasted effort anyway. However, my point of argument is the ideals. The idea someone SHOULD provide something. That SHOULD should be towards browser vendors, not website owners.

>And that's totally fine! If you don't have separate color schemes, it would make no sense to include a toggle. But if you have separate color schemes, add a toggle.

I don't think it's fine in your scenario, and the current state of things. If we require websites to individually provide their own toggles, how will the user know a toggle is even available or not? It creates an inconsistent UX where some websites have toggles and others don't. How many Hacker News visitors wasted time looking for a dark mode toggle that doesn't exist?

Which is why having it at the browser-level is necessary. Not to mention storing state, one of my pet peeves is using Incognito and losing my preferences.

It's kind of funny to me because Alternative Stylesheets solved this problem decades ago. Just like how Firefox used to have an RSS icon so we knew a website had RSS without needing to look for it. All of this stuff has been delegated to web extensions, which is barely supported on mobile. So we all need to plaster our websites with what we do and don't support and hope users find them.


> If it's not hard, shouldn't that ideal be towards the handful of browser vendors rather than the thousands/millions of website owners? I agree, if you're going out of your way to provide different stylesheets, provide a toggle, otherwise it's kind of a wasted effort anyway. However, my point of argument is the ideals. The idea someone SHOULD provide something. That SHOULD should be towards browser vendors, not website owners.

I want browser vendors to include a scheme toggle. Until this is present, I want website owners to include a scheme toggle. I don't care about the ideals while they degrade user experience for no good reason. Your website won't break once the browser toggle is implemented.

> I don't think it's fine in your scenario, and the current state of things.

I have no idea what you're trying to say. What I said in your quoted example is: you don't have to include multiple color schemes. Why do you think it's not fine? Why do you expect website owners to include multiple color schemes?

> If we require websites to individually provide their own toggles, how will the user know a toggle is even available or not? It creates an inconsistent UX where some websites have toggles and others don't.

Inconsistent UX is better than non-existent UX. You're asking for website owners not to include a toggle. How is that better than having inconsistent toggles which force me to change my whole OS color scheme just to change the scheme of your website? You're not explaining any advantages this has for the UX. Because it's pretty freaking terrible UX to do so.


>You're asking for website owners not to include a toggle.

I'm not. I'm saying they don't have to include a toggle if they don't see the need to. The decision is on them. No different from their decision to use specific colours, typefaces, text sizes, etc.

If the user has a preference, that toggle should be provided by the browser (the user agent) and the user should seek to get the browser to implement it rather than expect every website owner which has light/dark modes to provide a toggle.

In the current state of things, the browser is telling websites the user prefers a certain colour scheme, which may not even be true. That is really the core issue here if we focus in on dark/light toggles rather than the broader area of alternative stylesheets and ideal UX.

It feels in general that we are in agreement and may be misunderstanding specifics due to a lack of each other's contexts.


> It feels in general that we are in agreement here and may be misunderstanding specifics due to a lack of each other's contexts.

No, we're in fundamental disagreement. My position is very simple: you don't have to include multiple color schemes. If you do, you have to provide a toggle if you want your UX to not be shitty.

> I'm saying they don't have to include a toggle if they don't see the need to. The decision is on them. No different from their decision to use specific colours, typefaces, text sizes, etc.

But it's not like those other decisions. If a website owner decided to serve European customers double the font size that American customers are served, would you say "yeah, no reason to provide a toggle"? Because that's what you're suggesting - serving people different versions of the website without giving them a way to change it without changing their whole OS color scheme. Just for your website. What if I want to use two websites at the same time that follow your idea and want different color schemes? I can't.

> If the user has a preference, that toggle should be provided by the browser (the user agent) and the user should seek to get the browser to implement it rather than expect every website owner which has light/dark modes to provide a toggle.

But until that is implemented, you shouldn't force shitty UX on users. Don't decide for them or force them to switch up their whole OS color scheme just for your website. Don't make software harder to use than it needs to be just for ideological reasons.

> In the current state of things, the browser is telling websites the user prefers a certain colour scheme, which may not even be true.

Yes, so we should provide a toggle to change it. Don't force the user to change their whole OS color scheme.


It sounds like we're in agreement, you're arguing about things I didn't even say.

I just had a look, and Firefox already has the toggle. The only thing left is for them to provide a per-site toggle and it's sorted.

There are extensions which provide it: https://addons.mozilla.org/en-GB/firefox/addon/dark-mode-web...

Might be a matter of time before it becomes the norm.


Unless you walk back your initial statements I don't see why you'd think we agree, but you do you.


It should be the user that is granted control of this regardless of the mechanism. It is more convenient for the user to have a JS toggle in the browser, but a less convenient approach can also be provided on the back end. To the back end the only difference to the HTML, which is just string data, is a single class name on a single element.


This approach can be massively simplified by using CSS variables for your colors and only putting the color definitions in a separate file.


With consideration for accessibility this depends on the simplicity of the layout. In order to achieve WCAG 2.0 AA compliance color combinations must achieve at least a 4.5x luminosity ratio. That can mean different things may require color changes that were not required in the default scheme, as well as the opposite. As a result you really need files with different rules for that 20% that requires more than different color values.


> It was pretty sure, that dark mode can only be implemented using JS

I used this in the 90's:

`<body bgcolor="#000000">`

You needed it to really appreciate the sparks from animated fire gifs.


Yes you are right you can get dark mode by setting the background to black. But with this media query you get an automated switch between light and dark mode, depending on you browser settings.


Dark mode is much more than just bg color. Font, shadows, borders, selection, navbar, placeholders...


… which creates the kind of “dark mode” that ends up being unbearable. Dark mode does not mean pitch-black background, nor does it mean squeaky-white text color.


Most websites on geocities IIRC were "dark mode" :)


If white on black is unbearable, your screen contrast is miscalibrated. Lower it until comfortable.


If your screen shows pitch black and white both as a nice gray, your screen contrast is miscalibrated and you shouldn't be doing any work involving colors on it.


Ain't there yet but soon we should be able to do this without CSS

https://developer.mozilla.org/en-US/docs/Web/HTML/Element/me...


That is different, it styles the browser chrome rather than page content (at least in existing implementations). On desktop for example one can see the effect by using Vivaldi browser with a theme that has accent color enabled. It also is detected by sites like Discord for their embed widget accent color.


CSS only theme toggles are possible by utilizing a checkbox and placing the body content below the checkbox in a container element. Then adding a transparent label element that controls the checkbox state somewhere else on the page and styling a pseudo-button however one likes below the label.

Then in CSS setting both the prefers-color-scheme media queries but also configuring how the colors should react when the checkbox state is changed. So if a user has prefers-color-scheme:light then when the theme switcher is clicked it styles the page the opposite (example selector: .theme-switch:checked ~ .pagebody). Can also add such styling as a default outside of media queries, too, for browsers that don't recognize prefers-color-scheme.

Saving the state across pages however requires some JS but just wanted to comment that CSS-only toggles are possible.


It’s ironic it says that the user should set the theme themselves via their OS because the author doesn’t like to use buttons on sites to do it.

The vast majority of users don’t know how to do that. I’m sure the vast majority of that group couldn’t really explain themes as a concept.


For me what's compelling here is "auto-dark mode". As a user I don't want to keep making CSS changes to every site I visit to that's light mode. I wish the web in general had these 2 styles and automatically inferred from my device that "This person is a vampire, give him dark mode"


Original author here. I don't like the idea of using JS on my website and I don't think that it is possible to create a light/dark mode switch with only CSS. But you are right, most users don't know how to do that.


It is possible; just too convoluted/subpar imo. You can use a checkbox's check/uncheck status. One such codepen from quick google: https://codepen.io/shadowfaxrodeo/pen/JjbzNMz


Cool thank you for sharing this! I might implement this on my site.


You can! Trick is to use the checkbox:selected hack to apply styles, in addition to the colour-scheme media query.


However, it would probably be possible with very minimal JS a la how Tailwind does it, toggling a .dark class in the body element and setting the dark mode variables and colors there.


But adding onclick and window.open() JS functions is somehow justifiable, over using simple <a> links? Of course, there might be some specific case you are solving here, so it would be very educational to hear this out.


Would be perfectly reasonable to use js over this feature.


Yes for sure, but my personal policy is not using JS. Anyway my site doesn't have so many visitors ;-) People come, stay for a few seconds and then leave forever.


Hahah old school hate for js. Very good.


Not sure about Windows or macOS, there users probably stick with default setting anyway, but here on GNOME I have quick access to "Dark Style" toggle in quick settings, just one click away.

We could start a long discussion, should websites just follow system settings, or add their own custom controls, where you have different settings for each website. Along with dark mode switching, we should consider accessibility controls, and cookie settings too.

From a developer standpoint I'd prefer to reflect system settings.


If one can't set lightness mode in their OS, they almost certainly won't benefit with a button on the site.

Sites should follow the browser scheme (which usually follows OS) and can optionally provide a button to switch. This is possible with CSS only but too convoluted; one liner JS is enough for such optional cases.


> If one can't set lightness mode in their OS, they almost certainly won't benefit with a button on the site.

What could you possibly be basing this theory on?


Those who don't know how to do that probably don't care anyway.


If they don't know, how do you know they don't care? I find that if I show people a nice feature they did not know about, they often like it and then use it. It's just that not everyone is a tinkerer who first feels the need to dive into the features of a new software.


I'm pretty sure with all new CSS features theme toggle could be implemented without JS, but in that case it probably wouldn't reflect your current setting.


There's also:

`color-scheme: light dark`

which automatically switches the color scheme of default html elements depending on the preferred color scheme. No theming required!

https://garrit.xyz/posts/2023-04-12-instant-dark-theme


Very simple CSS only example, including JS-free toggling:

https://codepen.io/theprojectsomething/pen/oNQYqRw

Note: Could be simplified with the :has selector but it isn't currently supported in Firefox.


I just used CSS variables at my portfolio [0]. I just don't feel like adding a toggle in it to switch between light/dark mode adds something of special value in this case.

[0] https://miler.codeberg.page/


I implemented a dark mode on all of my websites. It has become so much easier with CSS variables. Just change the colour variables and the whole website goes dark.

The biggest challenge is images. You have to mind images with transparent backgrounds, as well as SVG icons with a fixed colour.


Sadly this isn't the best way to do it because you have no option to switch back to light scheme unless you manually do it in your System settings.


Thank you for sharing. But the problem could be, when some users don't want to the app to automatically switch to dark mode.


Uses SCSS which seems outdated.

Why not simply use native CSS variables? Worth pointing out since this is a post about doing something in a simple way.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: