Light and Dark Themes

Theme architecture should separate the semantic role of a value from its actual color. A surface token may be light in one theme and dark in another, while the component continues using the same property name.

CSS custom properties are a strong choice for runtime theme switching. A theme can be selected through an attribute or class on a root element, and all descendants can inherit the corresponding tokens.

Sass can generate the initial token declarations or organize theme data, but the browser handles runtime theme selection. For system preference support, consider the prefers-color-scheme media feature.

Test focus indicators, borders, disabled states, charts, illustrations, and shadows in both themes. Dark mode is not simply an inversion of every color.

Runtime Theme Switching
:root,
[data-theme="light"] {
  color-scheme: light;
  --surface: #ffffff;
  --text: #202020;
  --border: #dddddd;
}

[data-theme="dark"] {
  color-scheme: dark;
  --surface: #171717;
  --text: #f5f5f5;
  --border: #444444;
}

.panel {
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
}
💡 The theme attribute selects a set of custom-property values. The panel does not need separate component-specific selectors for every theme because it consumes semantic properties. The color-scheme declaration informs the browser about supported native UI color schemes. Explicitly test native form controls and other interface elements in each supported theme.
Knowledge Check

Which feature is especially useful for changing theme values without recompiling Sass?