CSS prefers-color-scheme Patterns and Best Practices

Learn patterns for implementing prefers-color-scheme with CSS variables, including fallback strategies, image handling, and transition effects.

Dark Mode

Detailed Explanation

Patterns for prefers-color-scheme

The prefers-color-scheme media query detects the user's OS-level theme preference. Combined with CSS custom properties, it enables automatic theme switching with zero JavaScript.

Basic Pattern

:root {
  --bg: #ffffff;
  --text: #111827;
  --border: #e5e7eb;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #111827;
    --text: #f9fafb;
    --border: #374151;
  }
}

body {
  background: var(--bg);
  color: var(--text);
}

Image Handling

Dark themes may need different image treatments:

img {
  filter: var(--image-filter, none);
}

@media (prefers-color-scheme: dark) {
  :root {
    --image-filter: brightness(0.9) contrast(1.1);
  }
}

For logos, use the <picture> element with media attributes or serve SVGs that reference CSS variables for fill colors.

Smooth Theme Transitions

Add a transition on the color-scheme change to prevent jarring switches:

:root {
  transition: background-color 0.3s ease, color 0.3s ease;
}

Caveat: Apply this transition only after initial render to prevent a flash-on-load. Many frameworks add a no-transition class during hydration.

Browser Support and Fallbacks

prefers-color-scheme is supported in all modern browsers (Chrome 76+, Firefox 67+, Safari 12.1+). For older browsers, the light theme defined in :root serves as the natural fallback — no extra code needed.

Testing Without Changing OS Settings

Chrome DevTools allows simulating prefers-color-scheme via the Rendering panel. This lets you test both themes without toggling your system appearance.

Use Case

Developers implementing automatic dark mode that follows the user's operating system preference, with proper handling of images, transitions, and browser fallbacks.

Try It — CSS Variable Generator

Open full tool