Kermode

/ˈkɜːrmoʊd/
The Spirit Bear

Written by Gray Gilmore

I make websites for a living. I love CSS and building simple and modular stylesheets. Somewhere along the way I also turned into a Ruby developer. Life comes at you fast I guess. You can read my resume to learn about my journey so far.

You can find me as @graygilmore on several platforms:

Good ol' fashion email works, too: hello@kermode.co

You can subscribe to this blog via RSS: XML, JSON

Give your site a dark mode with CSS variables

Kermode now has a dark mode! Right now this feature is only available for Safari 12.1 users or you trailblazers that are using Safari Technology Preview. Given that at the time of writing Safari 12.1 hasn’t been released I’ve included a toggle below if you want to get a taste of the change.

If you are using a browser that supports this and you’ve upgraded your operating system to macOS Mojave (10.14) you can toggle your “Appearance” preference between Light and Dark to see the changes happen automatically (General -> Appearance). Cool!

Media Queries are Powerful

Having this happen automatically for users that have set this preference is amazing. The magic behind this behaviour is built into a media query called prefers-color-scheme. It’s being discussed as a part of the Media Queries Level 5 Draft so it’s not quite ready for primetime but that doesn’t mean we can’t use it now as progressive enhancement!

If you’ve used media queries in CSS before you might be more familiar with this:

.foo {
  /* small screen styles */
}

@media screen and (min-width: 700px) {
  .foo {
    /* bigger screen styles */
  }
}

A media query is an important tool for writing CSS but it is much more powerful than the context that we normally think about it in. It can detect:

The Media Queries Level 5 proposal mentioned above aims to bolster this already multifaceted tool with some new features to test against.

Using this feature looks just about the same as any other media query. You use a key of prefers-color-scheme and set the value of the type that you want to target. In our case, we want to target dark preferences so our styles might look like this:

body {
  /* Default body styles. This is what the majority of your users will see until
  this feature is added to more browsers */
  background-color: white;
  color: rgba(0, 0, 0, 0.9);
}

@media (prefers-color-scheme: dark) {
  /* User prefers a dark color scheme so let's invert things to use a dark
  background-color and a lighter text color */
  body {
    background-color: #222;
    color: rgba(255, 255, 255, 0.9); /* A little nicer than using white */
  }
}

Rinse and repeat throughout your CSS and you’ll have a future-proofed site ready for dark mode. You can stop here and you’d be good to go but we can improve this implementation with the help of CSS variables.

Go Further with CSS Variables

One of the best features of CSS Variables is that their values can change dynamically (they are variable, afterall!). I wrote an introduction to CSS variables if you need a refresher on how this works. They’re super cool! One of their coolest features is that their value can change depending on media queries which we can use to clean up our implementation.

One of the problems with our implementation above is that we need to repeat our media query everywhere we want to adjust our design for dark mode. Knowing that CSS variables can be modified based on media queries we can rewrite the example above like this:

:root {
  --background-color-body: white;
  --color-text: rgba(0, 0, 0, 0.9);
}

@media (prefers-color-scheme: dark) {
  :root {
    --background-color-body: #222;
    --color-text: rgba(255, 255, 255, 0.9);
  }
}

body {
  background-color: var(--background-color-body);
  color: var(--color-text);
}

This approach allows us to consolidate our color definitions and prefers-color-scheme logic to a single location. This becomes really important as your stylesheet gets more and more complicated. We can continue to write styles as we normally would, utilizing CSS Variables along the way.

With this approach if we ever wanted to remove our dark color scheme we could remove a single block of code and be done with it. Or if we wanted to add another color scheme, maybe for high contrast devices, we’d only need to create a new media query and change our CSS Variables inside of it – no need to modify every CSS file in our application.