dark-mode-theming
Dark Mode Theming
When to use this
- You are implementing a light/dark theme toggle with system preference detection.
- You need to adapt brand colors, images, and illustrations for dark surfaces.
- You want elevation conveyed through lightness rather than shadows.
- You need to prevent the flash of wrong theme on page load (FOUC).
- Do NOT use this when you need to generate the color palette itself; use
color-oklch-palettesinstead.
Mental model
Dark mode is not inverting your stylesheet. It is a separate design surface with its own rules. Three principles govern it.
First: elevation is lightness, not shadow. In light mode, higher surfaces are lighter and cast shadows. In dark mode, higher surfaces are lighter too, but shadows are invisible (dark on dark). Instead, each elevation level gets a slightly lighter background. Material Design 3 uses 5 levels: 0% tint for the base, then +5%, +8%, +11%, +14% tint applied to the surface color. This means your dark surface colors form a stack from near-black upward.
Second: brand colors must be desaturated. A brand blue at oklch(0.55 0.2 250) that pops on a white background will vibrate painfully on a near-black background. Reduce chroma by 20-30% and push lightness up by 0.1-0.15 for dark mode. Never use the same accent color in both modes.
Third: pure black (#000) is almost never correct. It creates too much contrast with text and makes OLED screens look like the content is floating in a void. Near-black (oklch(0.14 0.005 250), roughly #1a1a1a to #1c1c1c) is the standard for a reason. The one exception is OLED-specific themes where battery savings justify true black; even then, use #000 only for the base surface.