Define a restrained surface hierarchy
Begin with a canvas and one or two panel surfaces. Pure white can be a panel while a slightly darker neutral separates the page background, but every extra near-white adds a distinction users must learn and maintainers must test. Assign each surface a role such as canvas, panel, raised panel, or selected region. Do not build hierarchy solely from tiny RGB differences that vanish on another display or under glare. Spacing, grouping, headings, borders, and elevation can reinforce the same structure. Record which foreground tokens are permitted on every surface before components start choosing arbitrary combinations.
Neutral surfaces do not have to be perfectly achromatic, but a tint should be intentional and consistent. A warm or cool bias changes how borders, shadows, images, and the accent appear. Check the palette on calibrated and ordinary displays without claiming identical perception for every viewer. Avoid using a tinted surface to imply success, warning, or error unless another cue communicates the status. User agents may replace colors in forced-colors mode, so semantic HTML and visible structure must survive. The light theme should remain understandable when decorative background differences are reduced or removed.
Make text levels readable by contract
Define primary, secondary, muted, and inverse text only when each level has a documented use. Primary text usually carries content; secondary text supports it; muted text may suit metadata but still needs sufficient contrast for its actual size and weight. WCAG 2.2 criterion 1.4.3 requires at least 4.5:1 for normal text and 3:1 for large text under its definition, with specified exceptions. A label does not become exempt merely because the design calls it subtle. Placeholder text also communicates information and should not be the only available label for a field.
:root {
--surface-canvas: #f8fafc;
--surface-panel: #ffffff;
--text-primary: #0f172a;
--text-muted: #475569;
--border-default: #cbd5e1;
--accent: #4338ca;
--focus-ring: #2563eb;
}Use borders and elevation for real jobs
Borders can separate panels, identify input boundaries, or decorate. The relevant requirement depends on their purpose. WCAG non-text contrast requires a 3:1 contrast against adjacent colors for visual information needed to identify user-interface components and states, with defined exceptions. A purely decorative divider is different from the only visible outline of an input. Do not make every line dark in response; instead, identify essential boundaries and give those enough evidence. Elevation and shadows may support grouping, but a soft shadow alone can disappear in high contrast, print, zoom, or bright ambient conditions.
- Canvas, panel, and raised surfaces with documented text pairs.
- Primary, secondary, and muted text tied to concrete content roles.
- Essential borders and focus indicators checked against adjacent colors.
- Accent background/on-accent pairs plus accent-on-surface variants.
Treat accent colors as paired roles
An accent is not one universally valid value. Treat accent backgrounds and their on-accent foregrounds as a tested pair, and separately test accent text or icons on light surfaces. A saturated color that works as a large button background may fail as small text on white. Links need a distinguishable affordance in context, including hover and visited behavior where relevant; color alone may be insufficient when surrounding text has similar contrast. Status colors need text, icons, labels, or patterns that preserve meaning. Keep destructive actions distinct through wording and interaction design, not only through a red hue.
| Role | Question to answer | Evidence |
|---|---|---|
| Surface | What hierarchy does it express? | Layout plus distinguishable boundary |
| Text | Where may this level appear? | Contrast result for each supported surface |
| Border | Is it essential or decorative? | Adjacent-color check when required |
| Accent | Which foreground belongs on it? | Tested pair for every interaction state |
Design focus and interaction states
Keyboard focus must be visible. A focus ring should contrast with the adjacent colors in the states where it appears, and it should not be hidden by overflow or replaced by a subtle shade shift. Use :focus-visible when it matches the desired input modality, while preserving a usable fallback for the supported browser policy. Hover, active, selected, disabled, and validation states each need deliberate pairs. Disabled content can have criterion-specific exceptions, but reducing contrast indiscriminately often harms readability. Do not use disabled styling for content that remains important to understand.
.card {
color: var(--text-primary);
background: var(--surface-panel);
border: 1px solid var(--border-default);
}
.control:focus-visible {
outline: 3px solid var(--focus-ring);
outline-offset: 2px;
}Measure contrast after compositing
Contrast calculations use final rendered colors. If text or a border has alpha, composite it over the actual surface before calculating relative luminance. A translucent panel over an image may produce many backgrounds, so a ratio measured over white alone is not representative. Gradients require checking relevant points behind the content. Anti-aliasing can make thin type look lighter, but conformance calculations use specified colors; practical review should still inspect typography at normal zoom and supported platforms. Keep source values and a reproducible contrast report so later palette changes can be reassessed.
- Measure normal text against the 4.5:1 criterion where applicable.
- Measure large text and essential non-text boundaries against applicable 3:1 criteria.
- Composite every translucent foreground over its real background.
- Inspect focus, hover, selected, disabled, error, and forced-colors states.
Validate the theme in complete screens
Validate complete screens, not only a token page. Cover forms, tables, navigation, dialogs, empty states, errors, selections, focus order, zoom, and content with long localized strings. Test automated contrast rules, then manually inspect cases involving images, gradients, transparency, icons, and component semantics. Try bright ambient light, reduced color differentiation, forced-colors, and system text scaling without asserting that one simulation reproduces every disability. Document failures with the exact pair and state. A light theme is ready when roles remain understandable and essential content remains perceivable across its supported contexts.
Primary sources
The factual claims in this article are checked against these published specifications.