CSS Tips: How I added Dark Mode to my website

Join the AI Workshop to learn more about AI and how it can be applied to web development. Next cohort February 1st, 2026

The AI-first Web Development BOOTCAMP cohort starts February 24th, 2026. 10 weeks of intensive training and hands-on projects.


Update: I now use Media Queries Level 5: prefers-color-scheme

The Media Queries Level 5 specification contains a new prefers-color-scheme media feature.

This is currently supported in all major browsers. Chrome/Edge since release 76, Firefox since 67 and Safari (since version 12.1). Even iOS Safari,

We can use it to tell if the user is browsing the page in dark or light mode:

@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}
@media (prefers-color-scheme: light) {
  body {
    background-color: white;
    color: black;
  }
}

I now use it to show a light version of the site by default, and a dark version if the system is in dark mode.

If the system does not have dark mode built-in (old Windows / macOS, Linux) then my suggestion is to use an extension like Night Eye or similar.

How I implemented dark mode before prefers-color-scheme was available

I recently redesigned my website. Here are 2 pictures of how it looked, for reference:

Old homepage

Old post page

I designed this website almost 1 year ago, and did many changes along the way, just as we do with any website.

Eventually I grew old of the design: title is too big, too much space lost instead of showing the content right on, and so on.

I sat down yesterday evening and started re-imagining the website, and I finished the redesign this morning:

New homepage

New post page

Much better! Content, the most important thing, is more prominent.

I used a monospaced font (Inconsolata) because as a programming blog it’s a nice one, despite the reduced readability and increased page size due to the font use, because I want that font on my site. I like it better, and since my site is a big part of my day to day activity, I wanted it to be like I want.

I just missed one thing: dark mode. As I was in the process of redesigning, I had the dark mode option in mind.

How did I do it? First, I added Moon Emoji 🌓 in the sidebar, as a way to let people change the mode from light to dark.

Then, I added a JavaScript snippet that runs when it’s clicked. I just added it to the onclick event handler inline in the HTML, without going fancier:

<p>
  <a href="#" onclick="localStorage.setItem('mode', (localStorage.getItem('mode') || 'dark') === 'dark' ? 'light' : 'dark'); localStorage.getItem('mode') === 'dark' ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')" title="Dark/light
</p>

This is the JavaScript that runs in the onclick:

localStorage.setItem('mode', (localStorage.getItem('mode') || 'dark') === 'dark' ? 'light' : 'dark'); localStorage.getItem('mode') === 'dark' ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')

It’s a bit convoluted, but basically I check if the mode property in the local storage is ‘dark’ (and defaults to dark if it’s not set yet, using the || operator), and I set the opposite of that in the local storage.

Then I assign the dark class to the body HTML element, so we can use CSS to style the page in dark mode.

Another script runs as soon as the DOM loads, and checks if the mode is dark. If so, it adds the dark class to the body HTML element:

document.addEventListener('DOMContentLoaded', (event) => {
  ((localStorage.getItem('mode') || 'dark') === 'dark') ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')
})

Now if people change mode, their choice will be remembered next time they load the page.

Then I added a lot of CSS instructions to the CSS, all prefixed with body.dark. Like these:

body.dark {
  background-color: rgb(14,20,10);
  color: #fff;
}
body.dark code[class*=language-],
body.dark table tbody>tr:nth-child(odd)>td,
body.dark table tbody>tr:nth-child(odd)>th {
  background: #282c34
}

Now things should already be working! Here is my site in dark mode:

Dark homepage

Dark post page

I added the dark class to the body element by default, to make dark mode the default:

<body class="dark">
  ...
</body>

Why? First, I liked it better. Then, I made a poll on Twitter and people liked it better.

Poll

But also for a technical reason, a very simple one actually. I don’t store the user choice server-side, so I have no way to know the mode until the local storage is available.

I could do that if the site was generated server-side, but it’s a static site, so I always serve the same page to everyone that requests it. Even if I got a cookie, I have no place to process it (on the flip side this means my pages load faster).

So when someone navigates to another page on my site, or loads the page for the first time on a second visit, I don’t want to show a bright page while I determine the mode. Maybe the visitor is coding in the middle of the night in a dark room.

I’d rather do that in light mode: show a dark page for a couple milliseconds and then turn it white again.

Lessons in this unit:

0: Introduction
1: How to center an element with CSS
2: CSS Border inside the element
3: What are good CSS Breakpoint values for Responsive Design?
4: How to debug CSS by bisecting
5: How to disable text selection using CSS
6: How to put an item at the bottom of its container using CSS
7: CSS, how to select elements that do NOT have a class
8: How to stick an element on the bottom of the page with flexbox
9: How to apply padding to multiple lines in CSS
10: Making a table responsive using CSS
11: CSS url()
12: How to make an element smaller or bigger with CSS
13: Customizing visited links
14: Fix extra space after inline element
15: How to create a sidebar that’s sticky but also scrolls
16: How to embed YouTube videos using the correct aspect ratio
17: Responsive pre tags in CSS
18: Responsive YouTube Video Embeds
19: How to remove all CSS from a page at once
20: ▶︎ How I added Dark Mode to my website
21: How to add a simple dark mode