A dark interface often needs more than one surface: a canvas, a raised card and a dialog or popover. A black shadow can be subtle against a near-black canvas, but it does not universally fail; its usefulness depends on the surrounding colors, blur and display. A tonal ramp is another way to show hierarchy. Flutter documents tone-based surface roles in its Material 3 ColorScheme, but the exact values below are original ColorIndicator tokens, not Material values or a Tailwind standard.
This example steps from Nocturnal Canvas (#0F1117) to Elevated Card (#161B26) and Floating Modal (#1F2637). Luminance Edge (#283246) is a fourth color token but a decorative border, not a fourth elevation surface. Crisp Alabaster (#F1F5F9) provides primary text. For accent directions, compare Cyber Cyan or Electric Chartreuse.
Why use a tonal surface ramp?
- Surface hierarchy: #161B26 is a slight step above #0F1117 (1.10:1), and #1F2637 is a slight step above #161B26 (1.14:1). These are gentle separations, not accessibility-verified boundaries for interactive controls.
- Text at every level: #F1F5F9 measures 17.22:1 on canvas, 15.73:1 on cards and 13.78:1 on dialogs. Those exact pairs exceed AAA for normal text.
- Muted text needs its own check: #94A3B8 measures 7.36:1 on canvas, 6.72:1 on cards and 5.89:1 on dialogs. It remains AA for normal text at all three levels, but only canvas reaches AAA for normal text.
Five tokens: three surfaces, one edge, one primary text color
Use the surface tones as a starting architecture, then inspect the actual cards, inputs, menus and focus states. The optional edge color is intentionally subtle: do not rely on it as the only required signal that an active control is present.
| Token role | Color | HEX | RGB | HSL | Suggested use |
|---|---|---|---|---|---|
| --color-surface-base | Nocturnal Canvas L0 | #0F1117 | 15, 17, 23 | 225°, 21%, 7% | Application canvas and inset areas |
| --color-surface-container-low | Elevated Card L1 | #161B26 | 22, 27, 38 | 221°, 27%, 12% | Cards, sidebars and grouped content |
| --color-surface-container-high | Floating Modal L2 | #1F2637 | 31, 38, 55 | 222.5°, 28%, 17% | Dialogs, popovers and menus |
| --color-border-subtle | Luminance Edge | #283246 | 40, 50, 70 | 220°, 27%, 22% | Decorative separation, not a sole essential control outline |
| --color-text-main | Crisp Alabaster | #F1F5F9 | 241, 245, 249 | 210°, 40%, 96% | Primary text on each tested surface |
To inspect an existing screenshot, analyze the image for its dominant digital colors; a screenshot does not establish the original physical display calibration. Browse the Palette Library for other starting points.
WCAG contrast across the three elevations
The ratios below are calculated from these specific sRGB HEX pairs. White and Crisp Alabaster exceed AAA for normal text on each listed surface. Muted Slate (#94A3B8) crosses below the 7:1 AAA threshold on the higher surfaces, though it remains above the 4.5:1 AA threshold.
| Foreground / background | Contrast | Normal text | Large text | Non-text cue |
|---|---|---|---|---|
| #FFFFFF / #0F1117 | 18.87:1 | AAA | AAA | Exceeds 3:1 where required |
| #FFFFFF / #161B26 | 17.23:1 | AAA | AAA | Exceeds 3:1 where required |
| #FFFFFF / #1F2637 | 15.10:1 | AAA | AAA | Exceeds 3:1 where required |
| #F1F5F9 / #0F1117 | 17.22:1 | AAA | AAA | Exceeds 3:1 where required |
| #F1F5F9 / #161B26 | 15.73:1 | AAA | AAA | Exceeds 3:1 where required |
| #F1F5F9 / #1F2637 | 13.78:1 | AAA | AAA | Exceeds 3:1 where required |
| #94A3B8 / #0F1117 | 7.36:1 | AAA | AAA | Exceeds 3:1 where required |
| #94A3B8 / #161B26 | 6.72:1 | AA; not AAA | AAA | Exceeds 3:1 where required |
| #94A3B8 / #1F2637 | 5.89:1 | AA; not AAA | AAA | Exceeds 3:1 where required |
| #283246 / #161B26 | 1.34:1 | Below AA | Below AA | Decorative only |
WCAG AA text contrast requires 4.5:1 at normal size and 3:1 for large text (at least 18pt regular or 14pt bold); AAA text contrast requires 7:1 and 4.5:1 respectively. Non-text contrast requires 3:1 for visual information needed to identify active controls, states or meaningful graphics. Not every decorative border is subject to that threshold. Evaluate the actual focus indicator, text, adjacent surfaces and state cues separately.
For AAA normal-size metadata on #1F2637, a separately tested lighter token such as #CBD5E1 measures 10.17:1. The #283246 border measures only 1.34:1 against a #161B26 card and 1.18:1 against #1F2637. It may indicate decorative grouping, but it cannot be the sole necessary cue for an active input or focused control. Disabled controls are exempt from SC 1.4.11; visible active and focus states still need their own tests.
The base-to-card and card-to-dialog surface steps are intentionally subtle. Legible content may identify a card without a 3:1 perimeter. An empty input, however, may depend on its border or fill to be recognized. Test the final component and adjacent colors in the Contrast Checker; inspect channel values in the HEX to RGB Converter.
Production CSS token architecture
Scope the three surfaces to the dark theme and keep typography separate from decorative borders. The optional #38BDF8 accent and #7DD3FC hover color below are additional example tokens; test them against their real adjacent surfaces before using them as essential indicators.
:root[data-theme="dark"] { --color-surface-base: #0F1117; --color-surface-container-low: #161B26; --color-surface-container-high: #1F2637; }:root[data-theme="dark"] { --color-border-subtle: #283246; --color-text-main: #F1F5F9; --color-text-muted: #94A3B8; --color-brand-primary: #38BDF8; --color-brand-primary-hover: #7DD3FC; }.ui-card { background-color: var(--color-surface-container-low); color: var(--color-text-main); border: 1px solid var(--color-border-subtle); }.ui-modal, .ui-dropdown { background-color: var(--color-surface-container-high); color: var(--color-text-main); border: 1px solid var(--color-border-subtle); }
These CSS snippets express a hierarchy, not a complete accessible component library. Recheck menus, dialogs, focus outlines, icons, borders and text when the implementation changes.
Frequently asked questions
Must a dark-mode canvas avoid pure black?
No. Pure black is not inherently inaccessible. This example starts with #0F1117 to leave room for three distinguishable surface roles. Whether that feels preferable depends on the product, display and user; test the rendered design rather than assuming a universal comfort benefit.
Does every elevated card need a 3:1 border?
No. WCAG non-text contrast applies to visual information required to identify a control or state, not every decorative card perimeter. If a border is the only necessary cue for an active input or its focus state, that cue needs at least 3:1 against adjacent colors.
Does muted text remain readable on each elevation level?
#94A3B8 measures 7.36:1 on #0F1117, 6.72:1 on #161B26 and 5.89:1 on #1F2637. All three pass AA for normal text; only the first also reaches AAA for normal text. Check any other background separately.
Where can I test a dark surface and text pair?
Enter the exact foreground and background in the ColorIndicator Contrast Checker. The HEX to RGB Converter displays the corresponding RGB and HSL values.
Run each real pair through the Contrast Checker, then use the HEX to RGB Converter for its channel and HSL values.