Chromatic Studios Logo Chromatic Studios Contact Us
Contact Us
Smartphone display settings screen showing light and dark mode preference options with system setting toggle interface

Using prefers-color-scheme Media Queries

Detect and respect your users’ system colour preferences automatically. This guide covers the media query syntax, browser support, and how to combine it with manual toggle controls for the best experience.

8 min read Intermediate April 2026

What’s prefers-color-scheme?

Here’s the thing — most of your users have already chosen light or dark mode in their system settings. They’re not starting fresh. They’ve made a preference, and respecting it creates a smoother experience from day one.

The prefers-color-scheme media query detects this choice automatically. It’s simple CSS, no JavaScript required. When someone visits your site, you can instantly apply their preferred theme without forcing them to toggle anything.

But here’s what we’ll cover — the syntax, how browsers handle it, and most importantly, how to combine it with a manual toggle so users aren’t locked into their system preference if they want something different on your specific site.

Quick Facts

  • Browser support is solid — 95%+ of users globally
  • Works on all modern browsers since 2019-2020
  • Zero JavaScript needed for basic implementation
  • Combines perfectly with manual theme toggles

The Media Query Syntax

The syntax is straightforward. You’ve got two options: light and dark . That’s it.

@media (prefers-color-scheme: dark) {
    body {
        background-color: #0a1628;
        color: #f0f9ff;
    }
}

@media (prefers-color-scheme: light) {
    body {
        background-color: #ffffff;
        color: #0f172a;
    }
}

You’ll write your dark theme styles inside the @media (prefers-color-scheme: dark) block and light theme styles in the light block. Simple as that.

Pro tip — structure your base styles as your default (usually light mode), then override with the dark media query. This ensures graceful degradation in older browsers that don’t recognize the media query.

Code editor showing prefers-color-scheme media query syntax with proper indentation and colour values highlighted for readability
Laptop screen showing browser developer tools with CSS media query rules panel open and colour swatches displayed for dark and light theme comparison

Real Implementation

Let’s walk through an actual setup. You’ll want to organize your colour values — either with CSS custom properties or by grouping related styles together.

The most reliable approach is using CSS variables. Define them once, then reference them in your media queries. You’re not duplicating colour values everywhere, and changes become simple — update the variable, everything updates automatically.

:root {
    --bg-primary: #ffffff;
    --text-primary: #0f172a;
    --text-secondary: #64748b;
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg-primary: #0a1628;
        --text-primary: #f0f9ff;
        --text-secondary: #bae6fd;
    }
}

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

This approach means you write your HTML and component CSS once. The media query handles switching all the variables. No duplicate selectors, no bloated stylesheets.

Combining with Manual Toggles

Here’s where it gets interesting. prefers-color-scheme is perfect for respecting system preferences, but what if someone wants dark mode while their system is set to light? That’s where a toggle comes in.

You don’t actually need JavaScript to implement this — well, you do need it to persist the choice, but the theming itself can be pure CSS. Add a data attribute to your HTML element, then use that attribute in your selectors.

html[data-theme="dark"] {
    --bg-primary: #0a1628;
    --text-primary: #f0f9ff;
}

html[data-theme="light"] {
    --bg-primary: #ffffff;
    --text-primary: #0f172a;
}

@media (prefers-color-scheme: dark) {
    html:not([data-theme]) {
        --bg-primary: #0a1628;
        --text-primary: #f0f9ff;
    }
}

The :not([data-theme]) selector is key here. When the user hasn’t manually chosen a theme, the media query applies. Once they click the toggle, the data-theme attribute takes over and overrides the system preference.

Mobile phone interface displaying a theme toggle switch button in header with sun and moon icons and current theme setting indication

Browser Support & Fallbacks

The good news — support is genuinely solid now. Chrome, Firefox, Safari, Edge all support it. Even mobile browsers handle it properly. We’re talking 95%+ of global users.

The small percentage without support? They’ll get your base theme — whatever you define outside the media queries. This is why structuring with a default light theme first, then overriding with dark mode in the media query, works so well.

Chrome

76+ (2019)

Firefox

67+ (2019)

Safari

12.1+ (2019)

Edge

79+ (2020)

Best Practices

You’ve got the syntax. Now here’s how to actually implement this without creating maintenance headaches.

Test Both Modes

Don’t assume your dark mode looks good. Check it. Seriously. Open developer tools, simulate dark mode, and scroll through every page. Look for contrast issues, check that images still work, verify that all text is readable.

Use CSS Variables Consistently

Don’t mix hardcoded colours with variables. Pick one approach and stick with it. Variables are cleaner, easier to maintain, and prevent the mess of having colour values scattered everywhere.

Provide Manual Override

System preferences are a great default, but some users want control. A toggle button respects that choice. It’s not complicated — one data attribute and a few lines of JavaScript to save their preference.

Consider Images and Graphics

Some images might look odd in dark mode. White backgrounds show up too bright. You’ve got options — use CSS filters, provide separate image variants, or adjust opacity. Think through each image.

Designer reviewing design mockups on multiple screens showing light and dark theme variations side by side for comparison and testing

Wrapping It Up

prefers-color-scheme isn’t a fancy feature — it’s a respectful one. Your users have already chosen their preference. You’re just acknowledging that choice and making their experience smoother from the moment they land on your site.

Start simple. Get the media query working. Use CSS variables for your colours. Test both modes thoroughly. Then, if you want, add a manual toggle so users can override if they need to.

That’s it. No massive JavaScript libraries, no complicated frameworks. Just CSS doing what it’s designed to do — adapt to the user’s environment.

Educational Information

This guide provides educational information about implementing dark mode detection and theme switching using CSS media queries. Implementation approaches, browser support details, and code examples reflect best practices as of April 2026. Your specific implementation may vary depending on your project requirements, existing codebase, and target audience. Always test thoroughly across different devices and browsers before deploying to production. Code examples are intended as learning references — adapt them to your particular design system and colour palette.

Marcus Wong, Senior Frontend Architect

Author

Marcus Wong

Senior Frontend Architect

Senior Frontend Architect at Chromatic Studios with 12 years specializing in dark mode implementation, CSS theme systems, and bilingual web accessibility for Hong Kong enterprises.