Contents

What CSS variables are

CSS custom properties — named values that you declare once and use everywhere. Change the value in one place — it changes everywhere. (If you're just getting into modern CSS, also check Flexbox vs Grid.)

/* Declare variables in :root — they are global */
:root {
  --bg: #ffffff;
  --text: #111111;
  --accent: #0066cc;
}

/* Use them */
body {
  background: var(--bg);
  color: var(--text);
}

Adding a dark theme

Create a second set of variables. They override the light ones whenever html has the attribute data-theme="dark".

:root {
  --bg: #ffffff;
  --bg-card: #f5f5f5;
  --text: #111111;
  --text-muted: #666666;
  --border: rgba(0,0,0,0.1);
}

[data-theme="dark"] {
  --bg: #0a0a0f;
  --bg-card: #111118;
  --text: #e8e8f0;
  --text-muted: #6b6b80;
  --border: rgba(255,255,255,0.07);
}

Switching via JavaScript

function toggleTheme() {
  const html = document.documentElement;
  const isDark = html.getAttribute('data-theme') === 'dark';
  html.setAttribute('data-theme', isDark ? 'light' : 'dark');

  // Save the user's choice
  localStorage.setItem('theme', isDark ? 'light' : 'dark');
}

// Restore the theme on load
const saved = localStorage.getItem('theme');
if (saved) document.documentElement.setAttribute('data-theme', saved);

Automatically follow system settings

You can skip the button entirely — CSS will pick up the system theme on its own (the same media-query approach as in responsive design):

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0a0a0f;
    --text: #e8e8f0;
  }
}

💡 You can combine: by default — system theme, but the user can toggle manually. Check localStorage first, then prefers-color-scheme.

Smooth transition

body {
  transition: background 0.2s, color 0.2s;
}

⚠️ Don't use transition: all — it slows down animations. Only specific properties: background, color, border-color.

Share: