How I’ve used light-dark() for light and dark mode

About three years ago, I wrote How to add dark mode to your website’, using media queries to switch themes.

That method still works but now there’s a simpler way. The light-dark() function is supported by all major browsers and ready for production use. You can check Can I Use for latest support.

The light-dark() function lets you pick one value for light mode and another for dark mode. The browser will automatically choose which one to use.

Using light-dark()

For light-dark() to work, you need to tell the browser your site supports both themes. Add this to your CSS using the :root selector.

:root {
    color-scheme: light dark;
}

Then apply light-dark() directly to a property like this:

color: light-dark(#4ade80, #219c4d);

This means:

  • In light mode, it uses #4ade80
  • In dark mode, it switches to #219c4d

Easier colour management

Using light-dark() on its own works, but defining your colours as custom properties helps even more. It makes your styles easier to reuse and update. In your CSS file define the colours you want to use as a custom property like this:

:root {
  --color-lime-600: #86efac;
  --color-lime-700: #219c4d;
}

This will allow you to reuse this colour elsewhere. For example like this:

color: light-dark(var(--color-lime-700), var(--color-lime-600));

If you need to change a colour later, you only have to do it once – it updates everywhere automatically.

To improve this further, I like to nest my CSS custom properties. For example, you could set a variable like this:

:root {
  --link-colour: light-dark(var(--color-lime-700), var(--color-lime-600));
}

You can then use this custom property wherever you need it. For example, applying it to links:

a {
  color: var(--link-colour);
}

How to use light-dark() with SVGs?

SVGs are tricky. The fill attribute in SVG can’t use light-dark() directly because it doesn’t work inline. To fix this, I swap the inline ‘fill' with a ‘CSS class’.

From this:

<svg fill="#219c4d">...</svg>

To this:

<svg class="fill-lime-200">...</svg>

I removed the inline fill="#219c4d" and added a ‘CSS class’.

Then in my CSS file I added:

.fill-lime-200 {
  fill: light-dark(var(--color-lime-200), var(--color-lime-800));
}

This lets the fill colour change with the theme, just like the rest of the site.

How to test dark mode

Testing dark mode requires changing settings on your device. Here’s a quick guide for various platforms:

Mac:

  • Go to System Preferences
  • Click on General
  • Choose Light, Dark, or Auto under Appearance

iPhone:

  • Open Settings
  • Go to Display & Brightness
  • Choose Light, Dark, or set to Auto

Windows:

  • Open Settings
  • Go to Personalisation
  • Click on Colours
  • Scroll down to ‘Choose your default app mode’ and select Dark

Android:

  • Open Settings
  • Go to Display
  • Tap on Dark Theme to toggle on/off, or set to Auto if available

The ‘auto’ setting changes modes based on the time of day.

Why use light-dark() instead of media queries?

In my old blog post ‘How to add dark mode to your website‘, I used @media (prefers-color-scheme: dark) to manage theme changes. It worked, but meant repeating styles inside a media query.

With light-dark(), I can write styles once and the browser picks the right colour. It’s shorter, easier to read, and plays nicely with CSS variables.

Tags

Leave a comment