If you’re here, you probably already know what dark mode is, so I’m not going to bore you with a long story about it. But if you want to read more about, here’s a very interesting article.

TL;DR: Dark mode is a color scheme of interfaces that display light text and elements on a dark background. Some say it’s for aesthetics only. Others say it mitigates digital eye strain, or even involved in the regulation of the circadian rhythm. Also, on AMOLED screens, it’s known to save more energy.

With that said, let’s dive right into the content:

A quick trick to make it “look like dark mode”

If you want to add dark mode to your website really quick, here’s a tip by Rik Schennink that I found on Dev.to:

html.dark-mode {
  filter: invert(100%);
}

html.dark-mode img {
  filter: invert(100%);
}

This will literally invert the colors of your website (although keeping the images the same color). That means white will become black and vice-versa, but also red will become green and blue will turn into orange (picture the color wheel now). In some cases, this will be fine, really, but if your UI has more colors and especially brand colors, inverting everything is not really what you want. I tried this on my blog just to see if I could get away with it and for the background and text it did work quite well, but for the tags (each has a distinct color) and for the header menu items, the inverted colors looked… weird...

Enters prefer-colour-scheme (or how to properly add dark mode)

Remember media queries? Yes, those @media that makes your block of CSS apply only at specific conditions (like min or max width of viewport). Well, what if I told you that not only can you use that to make a responsive layout, but you can also recognise when the user has dark mode activated on his OS or user-agent (browser, etc)? Yeah! That blew my mind when I figured that there are many many more media features you can use.

There’s one called prefers-reduced-motion which means the user prefers less motion on the page (the name of the property gives it away, I guess), inverted-colors which means the user agent has inverted colors, and yes, there’s one called prefers-color-scheme  which detects if the user, well, prefers a dark or light color scheme. If the user does not express any preference, it is assumed to be light.

Here’s how we can use this:

body {
  color: #464646;
  background-color: #FFF;
}

@media (prefers-color-scheme: dark) {
  body {
    color: #FFF;
    background-color: #3E3E3E;
  }
}

Now, if we had this setting in our CSS, and the user visited our website without any active color scheme preference, the font color would be that dark gray and background would be white. If they visit with a dark mode setting active on their system, the website would automatically apply the white color to the font and the darker color to the background.

What I like the most about this setting is that the user does not need to care about this setting on each website they visit. They can set this on their browser or OS, and it will be automatically detected and applied. I, for example, don’t like to use dark mode all the time, so I configured my OS to apply it only at night, so all the websites that use this CSS media feature will apply the light color scheme during the day and the dark mode during the night. Pretty cool, huh?

You could stop right here and go to your CSS and start applying this all over your website, but if you are already using TailwindCSS I’ll show you a cool trick that will make dark mode development much more enjoyable.

How to add custom media queries in TailwindCSS

So, let’s say I have a title of an article in my blog with the following TailwindCSS classes:

<h1 class="text-black text-2xl sm:text-3xl md:text-4xl mb-2">
	How to build a real time chat app with Node.js and Socket.io
</h1>

Nothing new here, just sets the title to be black and a different sizes at different viewports. Now, this is what I want to do:

<h1 class="text-black dark:text-gray-400 text-2xl sm:text-3xl md:text-4xl mb-2">
	How to build a real time chat app with Node.js and Socket.io
</h1>

This would be cool right? Just like we have the different sizes (sm, md, lg and so on) I would like to have the dark mode to be an option like that, so I can choose a color and immediately choose what that element will look like on dark mode. In order to do that, we need to add a plugin to TailwindCSS. So go to your tailwind.config.js and in the extends section, add:

module.exports = {
  theme: {
    extend: {
      screens: {
        dark: { raw: '(prefers-color-scheme: dark)' }
      }
    }
  }
}

That piece of code will tell TailwindCSS to add a custom media query to its set and now you can use just like the other ones.  By the way, you can use the same trick to style for any of those media features.

Now you could do: bg-white dark:bg-black or text-blue dark:text-purple or you know, go crazy with it! (Ok, maybe not, think of your users first).

Adding that scheme and using it inline and in CSS

If you’ve been using TailwindCSS for some time, you know that not always you can get the desired result only using the created classes, so you would have to write some CSS or PostCSS with `@apply` for example. Since we added that custom media query to the config file, you can also do something like this:

@screen dark {
  .MyArticle {
    @apply text-white;
  }
}

And that’s it! Hopefully you got inspired to add dark mode (or use an exotic media feature) in your web projects :) Are you going add dark mode to a project you’re working on? I’d love to see how you’ve done it, so tweet  @ me

Pro tip: if you’re in a website that does not support dark mode and you want to read something in dark mode, try the browser’s “reading mode”. For me at least, it seems to be easier on the eyes.