The CSS light-dark() function (Chrome 123+, Firefox 120+, Safari 17.5+) provides a shorthand for declaring two color values — one for light mode and one for dark mode — without duplicating the property inside a @media (prefers-color-scheme: dark) block. It works alongside color-scheme and integrates cleanly with CSS custom properties for full theme systems.
Problem: A WordPress theme implements a dark mode toggle using a prefers-color-scheme media query, but user-toggled dark mode preferences — stored in a cookie or localStorage — require duplicating colour values in JavaScript and CSS separately.
Solution: Use the CSS light-dark() function to declare both light and dark colour values in a single declaration: color: light-dark(#000, #fff). Toggle the active scheme at the :root level with color-scheme: light or color-scheme: dark from JavaScript — no CSS variable duplication is needed.
The examples below show basic light-dark() usage, a complete design-token system built on it, how to let the user toggle the scheme with a class, and integration with WordPress's theme.json duotone and color palette.
/* 1. Tell the browser this element supports both schemes */
:root {
color-scheme: light dark;
}
/* 2. Basic light-dark() usage */
body {
background-color: light-dark( #ffffff, #1a1a1a );
color: light-dark( #1a1a1a, #f0f0f0 );
}
a {
color: light-dark( #0073aa, #7cb9e8 );
}
/* 3. Design-token system using light-dark() inside custom properties */
:root {
--color-bg: light-dark( #fff, #121212 );
--color-surface: light-dark( #f5f5f5, #1e1e1e );
--color-border: light-dark( #ddd, #333 );
--color-text: light-dark( #111, #eee );
--color-text-muted: light-dark( #555, #aaa );
--color-accent: light-dark( #0073aa, #7cb9e8 );
--color-accent-hover:light-dark( #005580, #a8d4f0 );
--shadow: light-dark( 0 2px 8px rgb(0 0 0/.1),
0 2px 8px rgb(0 0 0/.5) );
}
.card {
background: var(--color-surface);
border: 1px solid var(--color-border);
color: var(--color-text);
box-shadow: var(--shadow);
border-radius: 8px;
padding: 1.25rem;
}
/* 4. Allow user-controlled toggle via data attribute on */
[data-theme="light"] { color-scheme: light; }
[data-theme="dark"] { color-scheme: dark; }
/* light-dark() automatically respects color-scheme on the element */
NOTE: light-dark() only works when color-scheme is explicitly declared on the element or one of its ancestors — it does not automatically inherit from @media (prefers-color-scheme) alone; always pair it with color-scheme: light dark on :root or the relevant container.