Recommended model
Preference: Auto, Light, Dark.
Resolved appearance: Light or Dark.
Theme values: semantic roles mapped to each appearance.
A durable color-mode system separates user preference, resolved appearance, semantic meaning, and rendered values. Light and dark are complete palettes. Auto is the resolver that selects one.
Store Auto, Light, or Dark.
Render only Light or Dark.
Map semantic roles, never raw inversion.
Test every state and preference.
Use semantic tokens as the contract. Auto is a live preference resolver, not a third palette.
Preference: Auto, Light, Dark.
Resolved appearance: Light or Dark.
Theme values: semantic roles mapped to each appearance.
Do not invert raw values. Reassign role-specific values for canvas, surfaces, text, borders, controls, focus, status, charts, and media.
Components remain unaware of appearance mechanics. They consume stable semantic contracts while the theme layer supplies appropriate values.
The distinction prevents Auto from becoming stale and lets analytics, debugging, browser chrome, and native controls remain synchronized.
Store auto, light, or dark. Do not persist Auto’s current resolution as the source of truth.
For server rendering, mirror the preference in a cookie when first-paint consistency justifies the added state.
theme-color.Media-qualified theme-color follows the system preference. When the product offers an explicit in-page override, update the matching metadata so the browser UI follows the product selection rather than the operating system.
Keep the knowledge model separate from component presentation through foundation, semantic, and component token layers.
Raw ramps and color-space values.
--blue-600 · --neutral-950Stable intent shared across products.
--color-action · --color-text-secondaryLocal bindings and state decisions.
--button-primary-bg · --input-focus-ring--white, --black, --light-grayThey describe appearance and become misleading across modes.
--surface-raised, --text-muted, --border-controlThey preserve intent while values change.
Both modes need readable text, distinguishable surfaces, explicit controls, coherent elevation, and tuned brand colors.
Primary cards and controls.
Nested or grouped regions.
Selected, code-adjacent, or inset regions.
Near-black text often reads more comfortably than absolute black. Separate decorative dividers from boundaries required to identify controls.
Not every product needs OLED black.
Use tonal change before heavy shadow.
Maintain visible structure at low luminance.
Bright saturated accents can bloom against dark fields. Tune lightness and chroma independently rather than reusing the light-mode value.
Use surface tone and border contrast first. Shadows are supplementary, especially in dark mode.
Keep an opaque baseline. Contrast over uncontrolled translucent content is nondeterministic.
Reserve it for media, cinematic surfaces, or an explicit OLED profile rather than making it the universal dark canvas.
WCAG 2.2 remains the production conformance gate. Emerging algorithms can supplement design analysis but do not replace current compliance.
| Content | WCAG 2.2 AA | Preferred product target | Operational note |
|---|---|---|---|
| Normal text | 4.5:1 | 7:1 when practical | Includes meaningful secondary and helper text. |
| Large text | 3:1 | 4.5:1 | Approximately 24px regular or 18.66px bold. |
| Essential UI boundaries and graphics | 3:1 | 3.5–4.5:1 | Decorative separators are evaluated differently. |
| Focus indication | Visible and unobscured | Two-color, multi-surface ring | Focus Appearance adds stronger AAA guidance. |
WCAG 2.x sRGB ratio for opaque hex colors.
Secondary information still carries meaning.
Dates, metadata, help text, breadcrumbs, and status explanations remain meaningful text.
Inactive controls may be exempt from specific contrast criteria, but should remain identifiable and understandable.
Pair hue with text, icons, shape, pattern, position, or accessible status announcements.
contrast-color() requires guardrailsIt is newly available in Baseline 2026, but currently resolves only to black or white. Mid-tone backgrounds can still produce inadequate small-text results. Restrict input ranges, provide fallbacks, and validate the final pair.
WCAG 3.0 remains a Working Draft and does not replace WCAG 2.2. Use alternative perceptual contrast methods as design-analysis signals only. Keep WCAG 2.2 AA as the formal production gate until applicable standards and policy change.
sRGB is the required baseline. OKLCH improves palette construction. Display P3 and HDR are progressive enhancements, not correctness dependencies.
sRGB: compatibility, remote desktops, screenshots, mixed displays, and default UI assets.
OKLCH: perceptual lightness, coherent ramps, interpolation, and independent chroma control.
Display P3: additional gamut for supported devices after the sRGB path already works.
Perceptual lightness makes systematic ramps easier to reason about than HSL. Equal lightness does not guarantee equal WCAG contrast.
Validate the sRGB fallback and wide-gamut override independently. Gamut mapping can change the final rendered result.
color-gamutIndicates approximate device and user-agent gamut support. It does not prove display calibration or exact appearance.
Embed appropriate profiles in raster assets. Verify optimization, screenshot, PDF, and export paths do not strip or reinterpret them.
Keep core UI in SDR. Reserve HDR for media and specialized visualization where hardware variability and glare are explicitly managed.
color-scheme affects native controls, scrollbars, spellcheck indicators, the canvas, and other browser-rendered UI.
accent-color is useful progressive enhancement, but current compatibility is not universal. Native controls must remain usable when it is ignored.
Use the color-scheme metadata before CSS to reduce mismatched initial canvas flashes.
Use :root { color-scheme: light dark; } so browser-provided controls can adapt.
Synchronize theme-color and any theme-aware favicon or manifest behavior.
currentColor for monochrome SVG icons.<picture media> for essential art direction.light-dark() image support as progressive until your browser matrix is verified.Font smoothing hacks are non-standard and can thin glyphs, especially bright text on dark backgrounds. Optimize font selection and metrics instead.
Omit global font-smoothing overrides.
font-optical-sizing: autoUse the font’s optical-size axis when available.
Provide intended weights and scripts; avoid accidental synthetic styling.
-webkit-font-smoothing is non-standard and platform-specific.
optimizeLegibilityUse rendering hints only after controlled cross-browser tests.
Preserve mobile and user-level text scaling behavior.
Test small text at ordinary pixel density and 100%, 125%, 150%, and 200% scaling. Avoid compensating for weak contrast with thinner type.
Native scrolling protects keyboard behavior, touch momentum, history restoration, find-in-page, and assistive-technology expectations.
Use smooth behavior for navigation, not for direct wheel or touch control. Disable it under reduced motion.
Use scroll-padding and scroll-margin so focused and linked content is not obscured.
scrollbar-gutter: stable reduces width shifts where classic scrollbars consume layout space.
Apply overscroll containment to nested panes only when scroll chaining is undesirable.
Do not replace native scrolling with transform-driven canvases, wheel interception, or mandatory full-page snapping for ordinary content.
Color scheme, contrast, forced colors, motion, transparency, data use, gamut, and dynamic range represent distinct adaptation dimensions.
forced-colors and prefers-contrast are broadly available. prefers-reduced-transparency remains experimental and limited, so the opaque design must be the dependable baseline.
The production pattern below uses native scheme negotiation, semantic tokens, one compact theme control, persisted preference, and synchronized browser chrome.
light-dark()Checkingcontrast-color()Checkingoklch()Checkingcolor(display-p3)Checkingscrollbar-gutterCheckinglight-dark(), OKLCH, P3 detection.contrast-color() for constrained backgrounds.:root {
color-scheme: light dark;
/* sRGB fallbacks first */
--canvas: #f7f8fb;
--surface: #ffffff;
--text-primary: #171b23;
/* Modern adaptive values */
--canvas: light-dark(#f7f8fb, #0d1016);
--surface: light-dark(#ffffff, #171c25);
--text-primary: light-dark(#171b23, #f2f5f9);
--text-secondary: light-dark(#4d5766, #bac3cf);
--border-control: light-dark(#909aa9, #697687);
--action: light-dark(#155eef, #8eb8ff);
--focus: light-dark(#005fcc, #9fc5ff);
}
:root[data-theme="light"] { color-scheme: only light; }
:root[data-theme="dark"] { color-scheme: only dark; }
html {
text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
scrollbar-gutter: stable;
scroll-padding-block-start: var(--sticky-offset, 4.75rem);
scroll-behavior: smooth;
}
body {
background: var(--canvas);
color: var(--text-primary);
font-optical-sizing: auto;
text-rendering: auto;
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
@media (prefers-contrast: more) {
:root { --text-secondary: var(--text-primary); }
}
@media (forced-colors: active) {
:focus-visible { outline-color: Highlight; }
}
type ThemePreference = "auto" | "light" | "dark";
type ResolvedTheme = "light" | "dark";
const systemDark = matchMedia("(prefers-color-scheme: dark)");
function resolveTheme(preference: ThemePreference): ResolvedTheme {
if (preference === "auto") {
return systemDark.matches ? "dark" : "light";
}
return preference;
}
function applyTheme(preference: ThemePreference): void {
const resolved = resolveTheme(preference);
document.documentElement.dataset.theme = preference;
document.documentElement.dataset.resolvedTheme = resolved;
// Synchronize browser chrome with explicit overrides.
lightThemeMeta.media = preference === "dark" ? "not all" :
preference === "light" ? "all" : "(prefers-color-scheme: light)";
darkThemeMeta.media = preference === "light" ? "not all" :
preference === "dark" ? "all" : "(prefers-color-scheme: dark)";
}
Theme quality depends on transitions, preference combinations, rendering environments, content stress, and first-paint behavior.
The document includes visible citations, section-level source mappings, structured metadata, a machine-readable provenance manifest, and explicit evidence classes.
Standards and WCAG requirements.
Browser behavior and compatibility.
Design-system and operating-system guidance.
Draft or limited-availability features.
Normative standards are treated as the source of truth. MDN is used for implementation and Baseline status. Platform guidance is advisory. Browser support and draft specifications can change after the research date.
This explainer does not constitute an automated accessibility conformance report. Real-device, assistive-technology, and product-context validation remain required.