Website Redesign: Dark Mode

I decided to jump on the ol’ bandwagon and implement a Dark Mode feature on this site. I’ve been interested in it for some time because, well, I use Dark Mode just about everywhere that offers it, from my computer and phone to specific apps, like Notion. I find it easier to read, especially these days, as my eyes have started showing signs of wear and tear.

There are different ways to implement dark mode, of course:

  • Using the prefers-color-scheme media query to set it according to a user’s operating system preferences
  • Adding a JavaScript-powered solution that swaps colors when clicked

I really like the idea of the second method because it opens up the possibility of other color themes down the road. At the same time, I like leveraging native browser features, so I went with the first method.

Turns out creating a dark mode with prefers-color-scheme is pretty darn simple. I sorta wonder why I waited so long. Although, I suppose I can say that after six years of leaving this site neglected.

Make some custom properties

Here’s how I made it happen. First, I used CSS custom properties to create variables for all of the colors I’m using in the design:

:root {
  --red: #fd1e1e;
  --orange: #fd5a1e;
  --gray-lightest: #f7f2f1;
  --gray-lighter: #e8e3e1;
  --gray-light: #cabdb9;
  --gray: #b0a3a0;
  --gray-medium: #7d7472;
  --gray-dark: #615a58;
  --gray-darker: #463e3b;
  --gray-darkest: #221d1b;
  --white: #fff;
  --black: #000;

Check out this ancient post of mine for more on my color-naming philosophy. It’s clearly evolved over time.

Once I had those in place, I abstracted them further into functional use cases. This allows me to update color values or swap out one color for another without needing to track them down in the code.

:root {
  /* same as before */
  --primary-color: var(--orange);
  --text-color: var(--gray-darkest);
  --background: var(--gray-lightest);
  --site-title: var(--gray-dark);
  --border-color: var(--gray);
  --link-border: var(--primary-color);
  --link-color: var(--text-color);
  --link-hover: var(--white);
  --link-current: var(--gray-darkest);
  --code-blocks: var(--white);
  --error-color: var(--red);
  --table-background: var(--gray-lighter);

Good so far, right?

Make some more custom properties

All that’s really left is to copy that second set of properties and paste them inside the prefers-color-scheme media query and change the values when dark mode is the selected preference.

@media (prefers-color-scheme: dark) {
  --text-color: var(--white);
  --background: var(--gray-darkest);
  --site-title: var(--gray);
  --border-color: var(--gray-lightest);
  --link-color: var(--white);
  --link-current: var(--white);
  --code-blocks: var(--black);
  --table-background: var(--gray-darker);

Ugh, that’s it

Seriously, that’s it. Now, when a user is in light mode, they get this:

Homepage screenshot in light.

…and when it’s dark:

Homepage screenshot in dark.

Would a button that toggles modes be cool? Sure! But that’s not what I was going for here. That said, I am indeed considering a San Francisco Giants mode in a future iteration. ⚾️

✏️ Handwritten by Geoff Graham on January 2, 2020(Updated on 10/19/2021)


  1. undefined
    # October 19, 2021

    Your code is broken, the only thing I see is stuff like this:

    <code>@media (prefers-color-scheme: dark) {
      --text-color: var(--white);
      --background: var(--gray-darkest);
      --site-title: var(--gray);
      --border-color: var(--gray-lightest);
      --link-color: var(--white);
      --link-current: var(--white);
      --code-blocks: var(--black);
      --table-background: var(--gray-darker);

    • # October 19, 2021

      Hey, thanks! Should be all fixed up.

Leave a Reply

Markdown supported