Skip to main content

Light and dark

Following advice in the article Native HTML light and dark color scheme switching from the wonderful HTMLHell website, I've added light and dark color controls to this site.

I've been wanting to do this for a while and finally got around to it. It uses the light-dark CSS function which is now widely supported.

The controls are in the bottom right of the page. If you can't see them then you're using a browser that doesn't support the light-dark CSS function. The fallback is the browser's default color scheme.

How it works

Jump to section titled: How it works

Some HTML:

<html>
  <head>
    <meta name="color-scheme" content="auto">
  </head>
  <body>
    <section class="scheme-switcher" aria-label="Color scheme switcher">
      <button aria-pressed="false" value="light">
        Light
      </button>
      <button aria-pressed="true" value="light dark">
        Auto
      </button>
      <button aria-pressed="false" value="dark">
        Dark
      </button>
    </section>			
  </body>
</html>

A little CSS (as an example):

body {
  background-color: light-dark(white, black);
}

A some JavaScript to wire it up (simplified):

button.addEventListener("click", () => {
  colorScheme.content = button.value;
  button.setAttribute("aria-pressed", true);
  localStorage.setItem("color-scheme", button.value);
});

As a bonus, make the controls only show up if the browser supports the light-dark CSS function:

.scheme-switcher {
  display: none;
}

@supports (color: light-dark(black, white)) {
  .scheme-switcher {
    display: flex;
  }
}

Conclusion

Jump to section titled: Conclusion

Some things I like about this implementation:

Supported on most modern browsers and doesn't screw things up for those that don't.

Update 4 May 2025

Jump to section titled: Update 4 May 2025

By making use of CSS properties and the @supports syntax, we can more gracefully fallback to, say, light mode if light-dark is not supported.

--background-color: #ffe;
--color: #333;

@supports (color: light-dark(black, white)) {
  --background-color: light-dark(#ffe, #220);
  --color: light-dark(#333, #ddd);
}

My proposition is that literal colour values in CSS are only used as properties and these are all defined like the ones above. Try and limit the range of colours you are using.

That's a little bit nicer than just using the browser default colours if light-dark isn't supported.