Forced colors / high contrast
themes specs/themes/forced-colors.kmd
How Koder UIs respond when the OS forces a high-contrast color palette (Windows High Contrast / `forced-colors: active`, and equivalent platform modes): defer to the user's system colors, keep every shape and focus ring visible via borders + system-color keywords, and degrade the Verge token layer gracefully. The OS-driven counterpart to the opt-in low-vision mode in a11y-modes.kmd. Fluent 2 + WCAG parity.
Quando esta spec se aplica
Triggers primários
- Implement forced-colors / high-contrast support in a Koder UI
Todos os triggers
- Support Windows High Contrast / forced-colors mode
- Make sure focus and borders stay visible under an OS color override
- Decide how Verge tokens degrade when the OS forces colors
Corpo da especificação
Spec — Forced colors / high contrast
Status: v0.1.0 — Draft. Promoted from the Microsoft Fluent 2 parity scan (meta/docs/stack #081); fills the "Windows high-contrast bridge / forced-colors (separate spec)" deferred by
specs/themes/a11y-modes.kmd. Sources: CSSforced-colorsmedia feature; Windows High Contrast; Fluent 2 high-contrast guidance.
R1 — Two distinct things
- Forced colors (this spec, OS-driven): the OS replaces the palette
(Windows High Contrast,
forced-colors: active). Koder does NOT pick the colors — it defers to the user's system palette. - Low-vision mode (a11y-modes.kmd, Koder opt-in): a Koder-chosen AAA-contrast theme the user enables in Settings. Independent; both can be active.
Detection is via the forced-colors: active media query (and the platform
equivalent on Flutter — highContrast/accessibility flags).
R2 — Defer to system colors
Under forced colors, map UI to the system color keywords rather than
brand tokens: Canvas/CanvasText (surface/text), LinkText,
ButtonFace/ButtonText, Highlight/HighlightText (selection),
GrayText (disabled), Field/FieldText. Let the OS resolve them; do not
hard-code hex in this mode.
R3 — Shapes survive (borders, not fills)
- Decorative backgrounds, shadows, and tonal elevation are typically flattened by the OS — so components MUST stay legible by border / outline, not fill alone. Add a 1px system-color border to surfaces that relied on background contrast (cards, inputs, buttons, menus).
- Never
forced-color-adjust: noneto "preserve branding" except for genuine content (e.g. a photo, a brand logo swatch) — never for chrome.
R4 — Focus and state always visible
- The focus ring uses a system color (
Highlight) and stays visible (it is the primary navigation cue when fills vanish). - Selected / checked / disabled states are conveyed by system-color + shape/icon, never by a brand fill that the OS will strip (pairs with the color-is-not-the-only-signal rule, WCAG 1.4.1).
R5 — Icons & images
- Symbolic UI icons (
specs/icons/ui-symbols.kmd) usecurrentColorso they inherit the system text color and remain visible. - Purely decorative images may be hidden under forced colors; meaningful images keep a text alternative.
R6 — Token-layer degradation
The Verge token layer (specs/themes/verge.kmd) defines forced-colors
fallbacks centrally so components inherit correct behavior without
per-component overrides; light/dark (specs/themes/light-dark.kmd) is
orthogonal (forced colors overrides both). Verification ties into the BR
conformance matrix (specs/accessibility/conformance-br.kmd).
Não-escopo
- The opt-in low-vision / color-blind modes (
specs/themes/a11y-modes.kmd). - The base light/dark contract (
specs/themes/light-dark.kmd). - Per-component visual specs (each owns its forced-colors border per R3).
Referências
specs/themes/a11y-modes.kmdspecs/themes/light-dark.kmdspecs/themes/verge.kmdspecs/accessibility/conformance-br.kmd