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 lightoronly 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.