× Search About Posts Code Music Links
Blank Try
experiment
lots
learn
more

Quick'n'dirty dark mode

Updated on
Last site update: 8 May 2024

So choosing a dark mode scheme can sometimes take a lot of time, particularly if your colours aren’t defined in CSS custom properties. But here’s and extremely quick way to get a new colour scheme in just a couple of lines:

1@media screen and (prefers-color-scheme: dark) {
2    html, img {
3        filter: invert(1) hue-rotate(180deg);
4    }
5}

If the user has their OS set to dark mode this CSS will invert and change all the colours.

Now note that img is in there along with HTML. What’s that doing there? Well if you just have html everything is inverted, including images. Assuming you don’t want your images changed then by adding img you are changing it twice. First they’re converted by the html and then they’re converted again by img which changes them back to how they should be.

No mobile ??

With this site for some reason the only thing which didn’t seem to work was the mobile slide out menu. Not sure of exactly why that was but in the spirit of quick’n’dirty I just added a few more characters of code to make sure these changes only happened when the full menu was active: and (min-width: 1001px) as in.

1@media screen and (prefers-color-scheme: dark) and (min-width: 1001px) {
2    html, img {
3        filter: invert(1) hue-rotate(180deg);
4    }
5}

If you’re not sure what this looks like because you don’t have dark mode set on your OS, you’re on mobile or maybe I’ve changed the colour scheme again here’s a screen shot:

quick’n’dirty dark scheme

Issues?

Now it’s not perfect and there’s something going on with Firefox around the bottom curved corner. There is presumably extra processing power needed to change the colours too.

Another thing is that the scroll bar kept the light scheme too. But overall I think the result is good and at least generates an idea for a new scheme starting point. With CSS custom properties you could quickly take the colours from this scheme and use them in the custom properties in the @media (prefers-color-scheme) declaration.

Going in the whole hog

So I decided to use the colours produced by the CSS filter in a proper way. Copying the colours wasn’t entirely straight forward. Using Color Picker browser extention could not choose the filter colours and instead picked the orginal ones. No use at all. Luckily I had the screen shot on the page so I picked the colours from there.

After copying the new colours into a root element in my dark scheme media declaration colour I commented out the filter and checked the results.

 1@media screen and (prefers-color-scheme: dark) and (min-width: 1001px) {
 2    
 3    /* html, img {
 4        filter: invert(1) hue-rotate(180deg);
 5    } */
 6    :root {
 7    --bgc: rgb(57, 24, 31);
 8    --bgc2: rgb(40, 62, 116);
 9    --bgc3: #683047;
10    --c: #69AFDC;
11    }
12}

Problem 1: the SVG’s colours

The first and expected problem was the svg wavy background colours. This SVG was set inline in the CSS file using

1main {
2    background-image: url("data:image/svg+xml...etc.");
3}

I thought about targetting this with the original filter settings but as it’s already part of the CSS file there’s no way targetting it (as far as I am aware).

The fill colours in SVGs apparently cannot take CSS custom properties. So what to do? I used a solution involving more custom properties of the SVG itself.

First I moved the original SVG into a custom property:

1 --bg-image: url("data:image/svg+xml ... etc.);

Then I duplicated this line and gave it a different name for the dark theme:

1 --bg-image: url("data:image/svg+xml ... etc.);
2 --bg-image-dark: url("data:image/svg+xml ... etc.);

Finally, using the search function of my editor for fill, I located the fill colours and changed the values to the colours I wanted. Then I just added this new custom property for the recoloured SVG to a main declaration in my dark scheme media query:

1main {
2    background-image: var(--bg-image-dark);
3}

NB. It’s possible to target SVG’s colour in CSS using the fill property. However this SVG had multiple fills as well as being part of the CSS file.

Problem 2: syntax highlighting

The next problem was the syntax highlighting in code blocks. These weren’t targetted by CSS file. The colours are generated by Hugo, my SSG, and inserted inline into the page. The obvious quick way was to use the filter again on code blocks.

1code {
2    filter: invert(1) hue-rotate(180deg);
3}

The only issue was this changed the background colour too because that was using a CSS custom property already and so was switched in dark mode. One way would be to remove the custom property in code declaration and just use a straight hex colour value of the original, light scheme, colour.

A different method

Lea Verou describes a completely different method.