CSS color-scheme Property and Dark Mode

The CSS color-scheme property allows developers to signal to the browser which color themes a website supports, enabling the browser to automatically optimize default interfaces—such as form controls, scrollbars, and system colors—for light or dark surfaces. By defining this property, you ensure native browser elements align with the user's system preferences or an explicit theme toggle without writing tedious overrides for every individual native control.

Understanding the color-scheme Property

The color-scheme property specifies the operating system color modes an element can comfortably render in. Unlike custom CSS variables or media queries that only change the styles you explicitly write, color-scheme directly instructs the browser engine to adjust its built-in styling mechanisms.

When declared, it influences:

  • Native form elements (buttons, inputs, select dropdowns, textareas, checkboxes, and radio buttons).
  • Browser scrollbars.
  • Default canvas backgrounds and text colors.
  • Spellcheck markers and other native browser overlays.

Syntax and Values

The property accepts several keyword values:

  • normal: The default value. The browser renders the element using its default color scheme, typically light.
  • light: Indicates the element supports and renders in a light color scheme.
  • dark: Indicates the element supports and renders in a dark color scheme.
  • light dark: Indicates the element supports both light and dark themes, allowing the browser to choose based on the user's operating system preferences.
  • only light or only dark: Restricts the element to that specific mode and opts it out of overrides caused by user-agent forced dark modes.

Basic Implementation

To declare that your entire application supports both themes, apply the property to the :root pseudo-class:

:root {
  color-scheme: light dark;
}

With this single declaration, if a user has their operating system set to dark mode, the browser automatically switches inputs, scrollbars, and background defaults to dark variants.

Toggling Dark Mode Styling

While setting color-scheme: light dark relies entirely on system preferences, modern websites usually offer a manual toggle (such as a switch in the navigation bar). You can control color-scheme programmatically to manage this transition.

1. Manual Toggle via Data Attributes or Classes

When a user selects their preferred theme via a UI toggle, you can update a data attribute or class on the root element using JavaScript, and adjust color-scheme accordingly:

:root[data-theme="light"] {
  color-scheme: light;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

When switched to dark, any native controls inside the document immediately convert to dark styling without requiring custom background and border overrides for every <select> or <input>.

2. Integration with the light-dark() Function

Modern CSS provides the light-dark() function, which depends directly on the computed value of color-scheme:

:root {
  color-scheme: light dark;
  --background: light-dark(#ffffff, #121212);
  --text: light-dark(#1a1a1a, #f0f0f0);
}

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

The light-dark() function evaluates the active color-scheme. If color-scheme resolves to dark (either through system preference or manual class assignment), it automatically selects the second parameter. If it resolves to light, it selects the first.

3. Per-Element Overrides

The color-scheme property is inheritable and can be applied locally to specific containers. For example, if you have a dark footer or a dark sidebar within an otherwise light website:

.sidebar-dark {
  color-scheme: dark;
  background-color: #222;
  color: #fff;
}

Any inputs, selects, or scrollbars inside .sidebar-dark will render using the dark browser theme, while the remainder of the page remains in light mode.

Preventing Theme Flashes with HTML Meta Tag

Before stylesheets load and parse, browsers determine initial rendering defaults. To prevent a flash of white background (FOUC) while loading a dark-mode page, declare support directly in the HTML <head>:

<meta name="color-scheme" content="light dark">

This ensures the browser renders initial backgrounds and native elements appropriately before your CSS files finish loading.