Concepts

forced-colors

Also: High Contrast Mode, HCM, Windows High Contrast, Forced Colors Mode

The CSS media query that detects user-configured high-contrast modes — primarily Windows High Contrast Mode, plus Chrome / Edge Forced Colors. Authors use it to adapt rendering when system colour preferences override site styles.

forced-colors is the CSS media query that detects when the user has turned on a forced-colour mode — typically Windows High Contrast Mode (HCM), which overrides website colour choices with a small system palette chosen by the user (white on black, black on white, yellow on black, or a custom palette).

Forced colour mode is heavily used by low-vision users, particularly those with light sensitivity or extreme contrast requirements. It’s also used as a personal preference by users without a documented disability who simply prefer high contrast.

What HCM actually does

When Windows High Contrast Mode is on, the OS replaces site colours with a small set of system colours:

  • Canvas — the page background.
  • CanvasText — the default text colour.
  • LinkText — link colour.
  • VisitedText — visited-link colour.
  • ButtonText — button text.
  • ButtonFace — button background.
  • HighlightText / Highlight — selected text colours.
  • GrayText — disabled text.
  • Mark / MarkText — highlighted text.

Browsers in forced-colors mode replace most author-defined colours with these system colours. They also remove background images and reset several visual properties to system defaults.

This is by design: the user has chosen a contrast palette that works for them, and they don’t want the site overriding that choice. The site’s job is to cooperate, not fight back.

The CSS media query

The author detects forced-colors mode with:

@media (forced-colors: active) {
  /* the user is in HCM or equivalent; adapt your CSS here */
}

The associated value prefers-color-scheme is independent — a user can be in dark forced-colors mode (white-on-black system palette) and their prefers-color-scheme query can still return light because the user hasn’t explicitly chosen “dark mode.”

What goes wrong in production

  • Background images become invisible. Forced-colors removes background images. If your “click to expand” caret is a background- image SVG with no fallback text, the user sees nothing. Fix: use <svg> or inline icons with currentColor so they pick up CanvasText; or provide a text fallback.
  • Borders disappear. Some borders are stripped or replaced with CanvasText-coloured borders. Visual hierarchy that depended on subtle border colours is gone. Audit your component borders in HCM.
  • Focus indicators stop working. Custom focus rings drawn with box-shadow lose their colour. Use outline (which is preserved) or detect forced-colors and provide a system-colour-aware fallback.
  • Visible-only-on-hover elements disappear permanently. Tooltip- style components that rely on background-image hover states fail.
  • forced-color-adjust: none. Some designers use this CSS property to opt out of forced-colors processing for a specific element. This is almost always the wrong choice — it means the user loses the colours they explicitly asked for. Use sparingly, only for truly-decorative elements where the design’s identity is essential (logos, brand-specific icons), and never on text or interactive controls.

How to test

Windows: Settings → Accessibility → Contrast themes → choose one of the built-in palettes (Aquatic, Desert, Dusk, Night sky) and reload the page. Chrome / Edge will pick up the system setting; Firefox uses its own forced-colors toggle in browser settings.

Most issues are caught on first inspection: missing icons, invisible borders, broken focus rings. Fix them with system-colour-aware CSS inside the forced-colors: active media query.