Dark interfaces are not simply light interfaces with a darker background. The relationship between surfaces, text, borders, and accents changes when the available luminance is compressed.
Build a surface hierarchy
Use several nearby surfaces rather than one black canvas:
- Base: the page background.
- Raised: cards, navigation, and dialogs.
- Interactive: buttons and focused controls.
- Muted: code blocks and secondary panels.
The differences can be subtle. A card should feel raised without glowing.
Contrast is a relationship
The same gray can be readable on one surface and disappear on another. Check text against the surface where it actually appears, including:
| Content | Check |
|---|---|
| Body text | Normal-size contrast |
| Metadata | Reduced opacity does not erase meaning |
| Links | Color plus another visual cue |
| Focus ring | Visible against every nearby surface |
| Disabled controls | Still distinguishable from the background |
Don’t use opacity as your only hierarchy
Opacity is useful for de-emphasis, but too much opacity makes important information look disabled. Prefer a deliberate text color for secondary content, and keep interactive elements visually distinct.
.muted {
color: color-mix(in srgb, var(--text) 68%, transparent);
}
.focus-ring:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
}
A quick review
View the page at low brightness, zoom to 200%, and navigate with the keyboard. If a label disappears or a focus state becomes ambiguous, the theme needs more than another accent color.