CSS light-dark() lets you provide two values for a color-related property: one for a light color scheme and one for a dark scheme. The browser chooses the value that matches the element's effective color-scheme. This can make a theme easier to maintain than repeating the same selectors inside many dark-mode media queries.
Use it for surfaces, text, borders, and other places that accept a color. The function is available in modern browsers; if you support older ones, keep a conventional fallback declaration first.
How light-dark() chooses a color
The syntax is light-dark(light-value, dark-value). The first argument is used in a light scheme; the second is used in a dark scheme. The values must be valid for the CSS property where you use them. The browser does not decide from the page's current background color. It uses the color-scheme setting.
Declare color-scheme: light dark on :root when your page supports both schemes. The browser can then follow the user's light or dark preference. You can also set color-scheme: dark or color-scheme: light on a component to force one scheme within it.
Example: Give a card two color sets
/* Allow the page to follow the user's color preference. */
:root { color-scheme: light dark; }
.card {
background: #fff; /* Fallback before the newer declaration. */
background: light-dark(#fff, #1e293b);
color: light-dark(#1e293b, #f8fafc);
border: 1px solid light-dark(#cbd5e1, #64748b);
}
The light card has a white surface and dark text. In a dark scheme, those choices reverse to a dark surface and light text. Notice that the border changes too; switching only the background may leave a component hard to read.
Try a complete light-dark() example
The following demo contains a scheme selector. Choose Light or Dark to set the card's color-scheme directly, or leave System preference selected to let the browser decide. You can edit the colors and run it again.
Example: Switch a card between color schemes
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>CSS light-dark() demo</title>
<style>
:root { color-scheme: light dark; }
body { font: 1rem/1.5 system-ui, sans-serif; margin: 2rem; }
.card {
max-width: 28rem;
padding: 1.25rem;
border-radius: .75rem;
background: #fff; /* Fallback for older browsers. */
background: light-dark(#fff, #1e293b);
color: light-dark(#1e293b, #f8fafc);
border: 1px solid light-dark(#cbd5e1, #64748b);
}
label { display: block; margin-bottom: .5rem; }
select { margin-bottom: 1rem; padding: .4rem; }
</style>
</head>
<body>
<label for="mode">Choose a color scheme</label>
<select id="mode">
<option value="normal">System preference</option>
<option value="light">Light</option>
<option value="dark">Dark</option>
</select>
<section class="card" id="card">
<h1>Reading card</h1>
<p>The same light-dark() rules adapt to the chosen scheme.</p>
</section>
<script>
// Change the scheme on this card without changing its CSS colors.
document.querySelector('#mode').addEventListener('change', (event) => {
document.querySelector('#card').style.colorScheme = event.target.value;
});
</script>
</body>
</html>
The dropdown changes the card's scheme, not each color separately. That is the benefit of this pattern: one scheme setting drives all of the card's light-dark() declarations. Its text, border, and background stay coordinated.
Use a fallback for older browsers
Write the ordinary declaration before the light-dark() declaration for the same property. A browser that does not understand the function ignores that later declaration and retains the earlier value. Choose a fallback with enough contrast, usually the light version if that is your default design.
Example: Keep a readable fallback
.notice {
background-color: #f1f5f9; /* Older-browser fallback. */
background-color: light-dark(#f1f5f9, #334155);
color: #0f172a;
color: light-dark(#0f172a, #f8fafc);
}
If you support older browsers and still require a complete dark theme there, add a prefers-color-scheme media query as part of your fallback strategy. A single light fallback alone will not create a dark theme in those browsers.
Practical checks
- Test both schemes, including keyboard focus, links, form controls, and disabled states.
- Check color contrast in both versions;
light-dark()selects colors but does not guarantee readability. - Set
color-schemeintentionally. Without both schemes enabled, the user's dark preference may not produce the result you expect. - Use a local
color-schemefor a themed component only when its descendants and built-in controls should follow that scheme too.
Conclusion
light-dark() pairs a light value with a dark one in a single CSS declaration. Enable the schemes your page supports, supply a readable fallback, and test the entire component in both modes. It is a concise way to keep related theme colors together while respecting the user's preference.