CSS Tutorial · Beyond the Basics · Lesson 17 of 19

CSS Variables and Dark Mode

Custom properties, theming and prefers-color-scheme.

Custom properties

CSS variables start with -- and are read with var(). Define them on :root to make them global, and override them anywhere:

Example 1Try it yourself
<style>
  :root {
    --brand: #2563eb;
    --radius: 10px;
    --space: 12px;
  }
  body { font: 14px system-ui; }
  .button { background: var(--brand); color: white; border: 0; border-radius: var(--radius); padding: var(--space); }
  .danger { --brand: #dc2626; }   /* override for one component */
  .card { border: 2px solid var(--brand); border-radius: var(--radius); padding: var(--space); margin-top: 10px; }
</style>
<button class="button">Primary</button>
<button class="button danger">Danger</button>
<div class="card">Border uses --brand: <code>var(--brand, fallback)</code></div>

Unlike preprocessor variables, custom properties are live: change one (even from JavaScript with el.style.setProperty("--brand", "red")) and everything using it updates.

Dark mode

Redefine the variables for dark mode — the components don't change at all:

:root { --bg: #ffffff; --text: #0f172a; }
@media (prefers-color-scheme: dark) {
  :root { --bg: #0f172a; --text: #e2e8f0; }
}
body { background: var(--bg); color: var(--text); }
Example 2Try it yourself
<style>
  .theme { --bg: #ffffff; --text: #0f172a; --muted: #64748b; --accent: #2563eb;
           background: var(--bg); color: var(--text); padding: 14px; border-radius: 10px; font: 14px system-ui; margin-bottom: 8px; border: 1px solid #e2e8f0; }
  .theme.dark { --bg: #0f172a; --text: #e2e8f0; --muted: #94a3b8; --accent: #60a5fa; }
  .theme small { color: var(--muted); }
  .theme a { color: var(--accent); }
</style>
<div class="theme"><strong>Light theme</strong><br><small>Muted text</small> · <a href="#">Link</a></div>
<div class="theme dark"><strong>Dark theme — same markup</strong><br><small>Muted text</small> · <a href="#">Link</a></div>

This site uses exactly this technique for its colour themes.

Test yourself

How do you read a CSS custom property named --brand?

  1. $brand
  2. var(--brand)
  3. --brand()
  4. @brand
Show answer

Answer: var(--brand)