Forced Colors & High Contrast

Windows High Contrast Mode and the CSS forced-colors media query replace custom colours with a small set of system keywords. Sitka components are authored to degrade gracefully and retain usability when colour is stripped.

What forced colors mode is

When a user enables Windows High Contrast Mode (or any OS-level forced-colors setting), the browser applies @media (forced-colors: active). Custom CSS colours are replaced by system colour keywords. Gradients, box-shadows, and background-images that convey meaning are stripped.

/* Detect forced-colors */
@media (forced-colors: active) {
  .my-button {
    /* Use system keywords — do not use hex or rgb */
    background: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonBorder;
  }

  /* Opt out for specific elements (use sparingly) */
  .custom-icon {
    forced-color-adjust: none;
  }
}

System color keywords

KeywordMaps toExample usage
CanvasPage/surface backgroundbackground-color: Canvas
CanvasTextPrimary body textcolor: CanvasText
ButtonFaceButton backgroundbackground: ButtonFace
ButtonTextButton labelcolor: ButtonText
HighlightSelected / focused elementbackground: Highlight
HighlightTextText on selected elementcolor: HighlightText
GrayTextDisabled textcolor: GrayText
LinkTextUnvisited linkscolor: LinkText
VisitedTextVisited linkscolor: VisitedText
ActiveTextActive (pressed) linkscolor: ActiveText
MarkHighlighted / marked textbackground: Mark
MarkTextText inside Markcolor: MarkText

Per-component rules

Button

  • Borders become visible — ButtonFace + ButtonText with ButtonBorder where supported
  • Transparent backgrounds are replaced by ButtonFace
  • Box shadows are stripped — use border instead for boundaries

Input / Textarea

  • Background → Field; text → FieldText
  • Placeholder text → GrayText
  • Focus ring becomes Highlight — verify outline width ≥ 2px

Checkbox / Radio / Switch

  • Custom drawn controls fall back to native appearance unless forced-colors overrides are defined
  • Use appearance: none + explicit Highlight/HighlightText for checked state
  • Use forced-color-adjust: none sparingly — only when full custom rendering is required

Badge / Chip

  • Coloured backgrounds collapse to Canvas — use borders as differentiators instead
  • Add a 1px ButtonBorder border so the element boundary is visible

Skeleton / Spinner

  • Animation fill colours become Canvas — add ButtonBorder to show boundaries
  • Consider showing static placeholder text instead of visual shimmer

Testing

Windows — native

  1. 1. Settings → Accessibility → Contrast themes
  2. 2. Choose High Contrast Black or White
  3. 3. Reload browser — forced-colors activates

Chrome DevTools — emulate

  1. 1. Open DevTools → Rendering tab
  2. 2. Find "Emulate CSS media feature forced-colors"
  3. 3. Select "forced-colors: active"

Guidelines

  • Never use colour alone to convey state — borders, icons, and text labels must also differ (this also satisfies WCAG 1.4.1).
  • Prefer borders over box-shadows for element boundaries — shadows are stripped in forced-colors.
  • Use forced-color-adjust: none only when absolutely necessary; it opts the element out of system colour replacement entirely.
  • Test with both High Contrast Black (dark) and High Contrast White (light) themes — behaviour differs.
  • Focus indicators must remain visible — ensure outline uses a system colour keyword in your forced-colors override.