Skip to main content
🎨 CSS as a design system·Module B5 · Lesson 14
TaskBuild a card that uses light-dark() for its surface + text colors. :root sets color-scheme light dark. .card has padding 20px, background light-dark(white, oklch(0.22 0 0)), color light-dark(oklch(0.20 0 0), oklch(0.95 0 0)), border 1px solid light-dark(oklch(0.90 0 0), oklch(0.30 0 0)), border-radius 12px.

light-dark(): one color, two themes, zero @media

100 XP8 min
Theory

A 2024 CSS feature you already wanted

You've been writing this for years:

:root { --bg: white; }
@media (prefers-color-scheme: dark) {
  :root { --bg: oklch(0.18 0 0); }
}

light-dark() collapses both into one expression:

:root {
  color-scheme: light dark;
  --bg: light-dark(white, oklch(0.18 0 0));
}

The browser picks the first argument when the user is in light mode, the second in dark. The color-scheme declaration tells the browser "this element supports both" — required for light-dark() to know what "light" and "dark" actually mean.

Why this is better than @media

  • Less duplication — each token defined once, both values inline.
  • Local overrides — a single component can swap its dark color without redefining the whole root variable cascade.
  • Forced-scheme APIscolor-scheme: only dark at a subtree level still works; light-dark() reads the cascaded value.

Browser support

Chromium 123, Safari 17.5, Firefox 120 — all shipped 2024. Use a fallback for older Chromium:

:root { --bg: white; }
@supports (color: light-dark(white, black)) {
  :root { --bg: light-dark(white, oklch(0.18 0 0)); }
}
@media (prefers-color-scheme: dark) {
  :root:not(:has(*)) { --bg: oklch(0.18 0 0); }  /* legacy path */
}

For greenfield 2026 code, just use light-dark() and accept that pre-2024 Chromium gets the first arg always.

🔒

Sign up to start coding

Theory is open to everyone. The interactive editor, live preview, and check are unlocked with a 7-day free trial — card required, cancel anytime.

Sign up — free trial →

First 15 lessons in each track are free. No card needed for those.

PreviousNext lesson →

Get one Python or web tip a day — by email

Short, hand-written, no spam. Unsubscribe in one click.