prefers-color-scheme: CSS Media Query

By  on  

One device and app feature I've come to appreciate is the ability to change between light and dark modes. If you've ever done late night coding or reading, you know how amazing a dark theme can be for preventing eye strain and the headaches that result. macOS recently implemented a native dark mode but that mode doesn't convert websites to a dark interface, so you're still getting a bright site regardless of native theme. Wouldn't it be amazing if websites would also go dark or light based on user's system preference?

The CSS working group agrees, which is why they've created a prefers-color-scheme media query; a media query that signals what the user's theme preference is and allows you to code your site to match that preference!

The prefers-color-scheme media query has two effective values you can specify: light and dark:

/* Light mode */
@media (prefers-color-scheme: light) {
    html {
        background: white;
        color: black;
    }
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
    html {
        background: black;
        color: white;
    }
}

Coupled with your default site design, you could potentially offer three different designs: default (no-preference), light modifications, and dark modifications.

To make managing colors in each mode easier, you can simply modify CSS variables within the media query:

/* Defaults */
:root {
    --color-scheme-background: pink;
    --color-scheme-text-color: red;
}

/* Light mode */
@media (prefers-color-scheme: light) {
    :root {
        --color-scheme-background: white;
        --color-scheme-text-color: black;
    }
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
    :root {
        --color-scheme-background: black;
        --color-scheme-text-color: white;
    }
}

/* Usage */
html {
    background: var(--color-scheme-background);
    color: var(--color-scheme-text-color);
}

If you want to use JavaScript to know which mode your user prefers, you can easily do so by getting a CSS variable value:

html {
    content: ""; /* (ab)using the content property */
}

/* Light mode */
@media (prefers-color-scheme: light) {
    html {
        content: "light"; /* (ab)using the content property */
    }
}

/* Dark mode */
@media (prefers-color-scheme: dark) {
    html {
        content: "dark"; /* (ab)using the content property */
    }
}
const mode = getComputedStyle(document.documentElement).getPropertyValue('content');

// mode: "dark"

I'm pleased that there's an official media query for color/theme preference. As someone who suffers from minor headaches to skull numbing migraines, my preference is always a dark theme and I appreciate apps that put in the extra effort to provide me a painless user experience. We already use media queries to accommodate print and different viewport sizes, so let's take an extra step in providing colors based on user preference!

Note: At the time of posting, only Safari Preview 68 has implemented this media query. Follow Bugzilla bug 1494034 to know Firefox's support status.

Recent Features

  • By
    9 More Mind-Blowing WebGL Demos

    With Firefox OS, asm.js, and the push for browser performance improvements, canvas and WebGL technologies are opening a world of possibilities.  I featured 9 Mind-Blowing Canvas Demos and then took it up a level with 9 Mind-Blowing WebGL Demos, but I want to outdo...

  • By
    fetch API

    One of the worst kept secrets about AJAX on the web is that the underlying API for it, XMLHttpRequest, wasn't really made for what we've been using it for.  We've done well to create elegant APIs around XHR but we know we can do better.  Our effort to...

Incredible Demos

  • By
    Geolocation API

    One interesting aspect of web development is geolocation; where is your user viewing your website from? You can base your language locale on that data or show certain products in your store based on the user's location. Let's examine how you can...

  • By
    Create Your Own Dijit CSS Theme with LESS CSS

    The Dojo Toolkit seems to just get better and better.  One of the new additions in Dojo 1.6 was the use of LESS CSS to create Dijit themes.  The move to using LESS is a brilliant one because it makes creating your own Dijit theme...

Discussion

  1. David S.

    Does window.matchMedia() not work for this?

  2. Timothy Hatcher

    Yes, matchMedia does work. So that would be better than using computed style.

    • Barry K.
      matchMedia('(prefers-color-scheme: dark)').matches
      matchMedia('(prefers-color-scheme: light)').matches
      

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!