Skip to content
WCAG & standards

Forced Colors: Supporting High Contrast Mode Properly

What forced colors mode does to your design, which properties fall away in the process and how to set up forced-colors, system colours and focus styles cleanly.

15 min read KontrastmodusCSSWCAG 2.2

High contrast mode is not a setting your page is politely asked to honour. It is a takeover: the browser discards the colour declarations in the document and replaces them with a small palette chosen by the user. What remains on screen shares only its structure with your design system. For interfaces that express state through fill colour, imply edges through shadows and build hierarchy through gradients, this is the moment of truth. This article explains what the mode actually triggers, which properties disappear without a sound, how the forced-colors media feature is used correctly, and where the European standard turns all of this into a requirement that shows up in an audit.

Key takeaways

  • In forced colors mode the browser forces the colour components of all properties to the user palette, not just text colour. Section 3.1 (W3C) of the CSS Color Adjustment Module records that box-shadow and text-shadow compute to none - edges made only of shadow vanish.
  • 19% (Web Almanac 2025) of sites now carry a forced-colors rule, but 20% (Web Almanac 2025) still rely on the superseded vendor query that Edge stopped evaluating altogether in version 138 (Microsoft Edge Blog).
  • 67% (Web Almanac 2025) of sites remove the browser's default focus outline. That outline is exactly what forced colors mode would hand back in a system colour; the method is set out in our article on focus management.
  • Clause 11.7 (EN 301 549) requires an interface to follow the platform settings for colour, contrast and focus cursor. High contrast mode therefore belongs in the scope of a WCAG audit, not in the category of optional extras.

What forced colors mode actually triggers

The starting point sits in the colour adjustment specification. When forced colors mode is active and forced-color-adjust is at its default value auto, the colour components of all properties on an element are force-adjusted to the user's preferred colour palette; that is how section 3.1 (W3C) of CSS Color Adjustment Module Level 1 describes it. This affects more than color and background-color: a long list of further properties is included, from the accent colour of a form control to the tap highlight on mobile devices. Two consequences of the same section cause most of the damage in practice: box-shadow and text-shadow compute to none, and background-image also computes to none unless the original value contains a url() function.

The state can be queried through a media feature of its own. Media Queries Level 5 introduces it in section 12.4 (W3C) under the name forced-colors with exactly two values: none and active. The value active means the browser is enforcing a limited, user-chosen colour palette on the page. The query tells you nothing beyond that. It does not report which colours were chosen, it names no luminance and it does not distinguish a light theme from a dark one. Inferring a particular palette from the active state builds on an assumption the operating system is free to overturn, because those colours are individually configurable there.

Two signals that get confused regularly

forced-colors and prefers-contrast describe different things. Section 12.3 (W3C) defines prefers-contrast with four values - no-preference, less, more and custom - and warns in the same section that using an unqualified prefers-contrast query to apply high contrast styles is incorrect: the value less means the opposite of what such rules deliver. forced-colors, by contrast, describes not a wish but a state in which the browser has already taken over the colour choice. The confusion is measurable in the wild: prefers-contrast appears on around 1% (Web Almanac 2025) of pages, forced-colors on 19% (Web Almanac 2025).

Who actually uses high contrast mode

The question of reach comes up reliably in projects, and it is a fair one. Solid figures are scarce, because a system-level mode is hard to count from inside the browser without making users identifiable. The best available source is a WebAIM survey from September 2018 with 248 (WebAIM 2018) valid responses from people with low vision. There, 51.4% (WebAIM 2018) report using some type of high contrast mode, and 30.6% (WebAIM 2018) name high contrast mode or settings explicitly among the assistive tools they use. The sample is small and self-selecting, it remains the most recent edition of that series, and it shows orders of magnitude rather than an official distribution. For an effort decision that is still enough, because the order of magnitude is unambiguous.

A second figure from the same survey changes construction more than the first one does. Among respondents who use a contrast mode, 71.2% (WebAIM 2018) work with light text on a dark background. Anyone who pictures high contrast mode as black text on white and writes their rules accordingly misses the majority of that group. In addition, 46.8% (WebAIM 2018) of all respondents name reduced contrast sensitivity as part of their visual condition - precisely the characteristic that a sharper separation between foreground and background addresses. The mode is therefore not a niche preference but an assistive setting with a clearly defined purpose.

Global scale

At least 2.2 billion (WHO) people live with a near or distance vision impairment. The same source puts the annual global cost of lost productivity at US$ 411 billion (WHO).

The German picture

At the end of 2023 around 7.9 million (Federal Statistical Office) people in Germany held a recognised severe disability. In 4% (Federal Statistical Office) of those cases the most severe disability was blindness or a visual impairment.

At the workplace

Windows ships four (Microsoft Learn) built-in contrast themes, namely Aquatic, Desert, Dusk and Night sky. Users can adjust them colour by colour on top of that, which is why a fixed assumption about light or dark does not hold.

These numbers do not replace a measurement of your own interface, but they frame the effort. And they meet a landscape that is already weak in its default state: low contrast text below the WCAG 2 AA thresholds was found on 83.9% (WebAIM Million 2026) of the one million most visited home pages, with an average of 34 (WebAIM Million 2026) separate instances per page. The same analysis detected an average of 56.1 (WebAIM Million 2026) automatically identifiable errors per home page, and 95.9% (WebAIM Million 2026) of home pages failed on machine-testable WCAG requirements alone. Only 31% (Web Almanac 2025) of mobile sites currently meet minimum colour contrast requirements. How to secure baseline contrast systematically is covered in our article on colour contrast in practice.

The palette belongs to the system, not to the design

In forced colors mode the colours come from a small set of system colours that CSS exposes as keywords. Canvas and CanvasText stand for surface and text, ButtonFace and ButtonText for controls, LinkText and VisitedText for links, Highlight and HighlightText for selection and focus, GrayText for disabled states, Field and FieldText for input fields. Inside forced colors mode these keywords are the only sensible way to set colour at all: any fixed colour value is replaced anyway, as long as the forced adjustment has not been explicitly switched off. The benefit of that restriction is reliability. An element that uses ButtonFace and ButtonText looks like every other system control in every contrast theme, without the page ever needing to know the colour values.

Why those palettes feel so hard is explained by the vendor documentation itself: contrast themes use a constrained colour palette with contrast ratios typically at or above 7:1 (Microsoft Learn), in order to improve readability, reduce visual fatigue and achieve a clear separation between foreground and background. That sits noticeably above the minimum of 4.5:1 (W3C) which the WCAG 2.2 success criterion Contrast (Minimum) requires for normal text at level AA. So as long as your own colour declarations do not override the system palette again, the mode supplies the contrast by itself - and a page that becomes harder to read in forced colors mode than in its default state almost certainly has a fixed colour somewhere that does not belong there.

forced-colors.css
/* The block only applies while the mode is active */
@media (forced-colors: active) {
  .card {
    /* System colours instead of brand colours */
    background-color: Canvas;
    color: CanvasText;
    /* The shadow is dropped, the edge has to stay */
    border: 1px solid CanvasText;
  }

  .action {
    background-color: ButtonFace;
    color: ButtonText;
    border: 1px solid ButtonText;
  }

  .action:focus-visible {
    outline: 3px solid Highlight;
    outline-offset: 2px;
  }

  .status-error {
    /* Colour alone carries nothing here any more */
    border-left: 4px solid CanvasText;
    forced-color-adjust: auto;
  }
}
Design deviceDefaultDark modeForced colors
Card fill colourbrand colour from the tokendark variant of the same tokenCanvas, chosen by the user
Edge made of box-shadowvisiblevisiblecomputes to none, section 3.1 (W3C)
Gradient backgroundvisiblevisiblecomputes to none, except with url()
Focus ring in a brand colourvisiblevisiblebecomes the system colour Highlight
State signalled by colour alonedistinguishabledistinguishableno longer distinguishable
Text on a coloured surfacemeasured contrastmeasured contrastsystem contrast, at or above 7:1 (Microsoft Learn)

The most expensive finding is not created in forced colors mode

It is created earlier, in the design system. If states such as active, selected, invalid or disabled are expressed through fill colour alone, forced colors mode leaves no means of showing them: every surface collapses onto the same system colour. The fix is not another media query but a second attribute per state - an icon, a changed border weight, a label. That pays off outside forced colors mode as well, because the WCAG criterion on the use of colour asks for exactly this double encoding, and because people with colour vision deficiencies benefit immediately.

What disappears without a sound

The dangerous effects of this mode are the ones that raise no error. Nothing breaks, nothing overlaps, and at first glance the page even looks tidier than before. A few edges are simply missing - and with them the information those edges carried. Five patterns show up especially often in audits, and all five can be fixed once in the design system rather than component by component.

  • Edges made of shadow. Cards, flyouts and dialogs whose boundary consists only of a box-shadow lose it with nothing in its place. For transitory surfaces the vendor documentation explicitly recommends a 2px (Microsoft Learn) border, because otherwise the transition between surface and underlying page disappears.
  • Gradients as backgrounds. A background-image with linear-gradient computes to none unless the value contains a url() function. If text sits on the gradient rather than on a surface of its own, it ends up on the system surface afterwards - usually readable, but the intended grouping is gone.
  • Icons as background images. An icon set through background-image with a data URL survives the forced adjustment but keeps its original colour. On a dark system background a dark icon becomes effectively invisible.
  • Inline SVG with a fixed fill. A graphic with a hard-coded fill does not follow the system palette. Using currentColor instead gives you the right colour without an extra rule and without a second asset.
  • Transparency as separation. Semi-transparent overlays, greyed-out regions and soft shadow edges lose their effect once every surface carries the same system colour. For disabled states, GrayText is available instead.

What stands out is that none of these patterns is an error in the narrow sense. Each is a shortcut that works in the default state and whose cost only becomes visible when colour authority changes hands. That is why a look into the component library pays off more than a look at an individual page: get a card, an input field and a dialog right, and most of the estate is treated along with them. How to capture that in reusable building blocks is described in our article on the accessible design system.

The focus outline is the most fragile point

No other design element is removed so often and replaced so rarely. 67% (Web Almanac 2025) of sites remove the browser's default focus outline, considerably more than the year before; the modern alternative :focus-visible, meanwhile, appears on only 25% (Web Almanac 2025) of desktop pages. These values do not come from a sample but from the monthly HTTP Archive crawl across 17 million (Web Almanac 2025) sites covering home and secondary pages. In forced colors mode the loss weighs double: the browser would hand the outline back in the system colour Highlight, but only if the page has not cleared it away first. An outline: none stays an outline: none there too.

WCAG 2.2 has, for the first time, put a measurable lower bound on this. The focus indicator must be at least as large as the area of a 2 CSS pixel (W3C) thick perimeter of the unfocused component and must show a clear contrast difference between the focused and unfocused states. The criterion sits at level AAA and is therefore not part of the usual audit scope, but it supplies a usable number for design work. In practice that means a solid outline rather than a hinted shadow, an offset from the element so the ring does not merge with the border, and an outline-color from the system palette inside the forced-colors block. For applications where focus moves programmatically, our article on focus management is worth reading alongside this one.

visible-focus.css
/* Visible focus across all three states */
.action:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
}

@media (forced-colors: active) {
  .action:focus-visible {
    /* System colour instead of brand colour */
    outline-color: Highlight;
  }
}

/* Border carries, shadow is a bonus */
.input {
  border: 1px solid var(--edge);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.08);
}

The second point concerns the borders themselves. The success criterion Non-text Contrast requires a contrast ratio of at least 3:1 (W3C) against adjacent colours for user interface components and their states. An input field whose boundary consists of a soft shadow in the default state no longer satisfies that in forced colors mode, because no boundary is left there at all. Working with border from the outset and treating the shadow as a bonus produces the same result in all three states and makes the special rule unnecessary. The same reasoning applies to table rules, to card outlines and to the edge of an active tab in a navigation bar.

forced-color-adjust: an exit with a price tag

There are cases where the forced adjustment harms rather than helps: a colour chart in a configurator, a diagram with colour-coded series, the preview of a selected paint tone, a traffic-light indicator in a report where the colour is the statement itself. For these the specification provides forced-color-adjust: none. The property switches the forced adjustment off for an element and its descendants; the colours then stay as the document set them. This is an exception with a price tag, because from that point on the page carries the responsibility for contrast again, and nobody knows what background the chosen contrast theme is currently supplying.

exception.css
/* Exception only where colour IS the information */
.swatch {
  forced-color-adjust: none;
  /* Own border, because the system no longer carries this */
  border: 2px solid CanvasText;
}

.swatch__name {
  /* Second encoding: the name sits next to it */
  forced-color-adjust: auto;
}

Three rules for the exception

First, it applies to the smallest possible element and not to a container: a forced-color-adjust: none on a section switches the assistive setting off for everything inside it. Second, any surface that keeps its own colour this way needs a border in a system colour so that it stands apart from the background at all. And third, every piece of colour-coded information needs a second encoding - a label, a pattern or a symbol - otherwise the statement still hangs on colour alone. What that looks like for data series is shown in our article on accessible data visualisation.

The superseded query and its silent damage

Before the standard there was a vendor route, and it is now history. The Edge team has completely removed the non-standard -ms-high-contrast media feature and its accompanying property, starting with version 138 (Microsoft Edge Blog). Anyone still relying on it has no high contrast rule at all in today's Edge: the block is not evaluated, no error is raised, and because no error is raised nobody notices. In the wild this is not an edge case. The superseded query sits in more pages, at 20% (Web Almanac 2025), than the standard that replaced it, at 19% (Web Almanac 2025) - a ratio that can only be explained by old templates and libraries carried along for years.

The standard, meanwhile, is anything but new. The forced-colors media feature is considered well established and, by the Baseline classification, has been available across browsers since September 2022 (MDN Web Docs). For a project starting today there is therefore no technical reason left for the vendor route; for an older project a targeted search for the legacy string in the stylesheet is worth the time, because it usually concentrates in a handful of places. The rewrite is normally mechanical: the condition changes, the colour values inside the block are replaced by system colours, and the special cases for individual values of the old query fall away entirely.

One subtlety with a large effect sits in the coupling to dark mode. Whether a contrast theme counts as light or dark is decided by the browser from the luminance of the forced background colour: in Chromium a forced background with a luminosity below 0.33 (Microsoft Edge Blog 2020) will match prefers-color-scheme: dark. Forced colors and dark mode can therefore apply at the same time without being the same thing. A rule that only handles dark mode then happens to be right or happens to be wrong in forced colors mode - and anyone writing both blocks should set their order in the stylesheet deliberately, because otherwise the later block wins without anyone having made that decision. If you want to handle user preferences cleanly in general, the systematic approach is in our article on prefers-reduced-motion.

Testing: three states, one pass

Forced colors mode cannot be judged from memory. It needs a pass of its own, and that pass stays short if it runs systematically. The quickest route is in the browser: the developer tools in Chromium browsers can force the forced-colors: active state without switching the operating system over. That is not sufficient for an acceptance test, because the emulated state uses a default palette while real users set their own colours. For day-to-day work on a component it is the shortest path, and for acceptance a pass on a real system with a contrast theme enabled is added.

  1. Open the page in forced colors mode and walk through it once with the tab key. Every stop has to be visible; where focus vanishes, the cause is almost invariably an outline: none without a replacement.
  2. Count every edge that exists in the default state and is missing in forced colors mode: cards, input fields, flyouts, dialogs, table rules, separators, active tabs.
  3. Step through every state of a component - default, hover, focus, pressed, selected, disabled, invalid - and check whether it is still distinguishable from the others.
  4. Look at icons and graphics: an icon that keeps its old colour is either a background image or an SVG with a hard-coded fill.
  5. Repeat the same pass in a light and in a dark contrast theme, because 71.2% (WebAIM 2018) of contrast mode users set light text on a dark background.
  6. Finally hold the default state against forced colors mode: anything that reads better in forced colors than in the original points to a contrast problem in the design itself.

In practice this order finds more than a tool report does, because it walks along states rather than along rules. Automated checks barely see forced colors mode anyway: they measure computed colours in the default state and report violations of contrast thresholds there - an edge that disappears in forced colors mode shows up in none of those reports. Which tool covers which part, and where machine testing ends, is set out in our overview of testing tools. It is also worth folding forced colors mode into your review of type and line handling, because thin weights behave differently on hard system colours; our article on accessible typography fits alongside that.

The European standard that Germany measures against has a clause of its own for this case. Clause 11.7 (EN 301 549) requires that software which is not designed to be isolated from its platform and which provides a user interface shall follow the values of the user preferences for platform settings - explicitly naming units of measurement, colour, contrast, font type, font size and focus cursor, except where the user overrides them. A note in the same clause makes clear that for web content the underlying platform is the user agent. The operating system's contrast mode, passed through to the page by the browser, is therefore exactly the setting an interface is expected to follow.

Two further references in the same standard close the loop to measurement. For web pages, clause 9.1.4.3 requires the WCAG success criterion 1.4.3 (EN 301 549) Contrast (Minimum) to be satisfied, and clause 9.2.4.7 requires success criterion 2.4.7 (EN 301 549) Focus Visible. At this point the standard prescribes no figures of its own but adopts the WCAG requirements unchanged. The associated measured value then sits there: at least 4.5:1 (W3C) for normal text at level AA. If you would like to read the framework in context, it is covered in our article on EN 301 549 and in the overview of the new criteria in WCAG 2.2.

Forced colors mode does not test an interface's choice of colours but the way it is built. Whatever falls apart without its own palette had colour doing work where structure should have been.

How to approach it in a project

The work stays manageable if it starts in the right place. Forced colors mode rarely uncovers a problem that concerns only forced colors mode; it makes shortcuts visible that sit in the design system. That is why it pays to pull it early into the component library rather than late into acceptance testing. A pass through the twenty most used building blocks covers the bulk of the interface in most projects, because cards, buttons, input fields and dialogs repeat across the whole application.

  • Review every edge in the design system that comes from a box-shadow and add a border as the load-bearing variant; the shadow stays a bonus.
  • Give every state a second attribute that is not colour - an icon, a border weight or a label.
  • Move focus styles to :focus-visible and set them to Highlight inside the forced-colors block; see also our article on keyboard navigation.
  • Move inline SVG to currentColor and replace icons that are wired up as background images.
  • Apply forced-color-adjust: none only where colour is the information itself, and give every such surface a system-coloured border.
  • Search for legacy -ms-high-contrast blocks and replace them with forced-colors, so the rules take effect again at all.
  • Add forced colors mode to the acceptance checklist alongside dark mode and the default state: three states, one pass.

What comes out of this reaches well beyond forced colors mode. A component that does not signal its states through colour alone stays unambiguous for people with colour vision deficiencies too. A focus ring that adopts the system colour works with a self-assembled contrast theme as well. And a design system that carries its edges instead of hinting at them becomes more robust in a place where it otherwise breaks regularly. If you want to assess your own estate, the relevant steps are in our accessibility services and in accessible web development; where maps and location search raise the same question, our article on accessible maps and store locators helps, and for applications behind a login, the article on the accessible intranet.

Sources and studies

This article is based on data from: the HTTP Archive Web Almanac 2025, accessibility chapter (user preferences, focus styles, colour contrast, methodology); The WebAIM Million 2026 on the accessibility of the one million most visited home pages; the WebAIM Survey of Users with Low Vision Number 2 from September 2018; W3C Media Queries Level 5 (sections 12.3 and 12.4); W3C CSS Color Adjustment Module Level 1 (section 3.1); W3C Web Content Accessibility Guidelines 2.2 (success criteria 1.4.3, 1.4.11 and 2.4.13); MDN Web Docs on the forced-colors media feature; Microsoft Learn on contrast themes in Windows; two posts from the Microsoft Edge Blog on forced colors; ETSI EN 301 549 V3.2.1 (clauses 9.1.4.3, 9.2.4.7 and 11.7); the German Federal Statistical Office, press release number 281 of July 2024; the World Health Organization fact sheet on blindness and vision impairment. The values quoted reflect the most recently published edition in each case.

Related Articles

WCAG & standards

Accessible Tooltips: Content on Hover or Focus (1.4.13)

Success Criterion 1.4.13 asks for three things at once: dismissible, hoverable, persistent. This article takes the wording apart, walks the BITV test path and.

15 min read
Practice & implementation

Accessible Maps: Store Locators Without Dead Ends

Map widgets fail audits with striking regularity. How a location search still works without a mouse, without colour perception and with a screen reader: list.

14 min read
German Accessibility Act

Accessible E-Learning: Platforms, Courses and Quizzes

Paid online courses fall under the BFSG, universities under BITV 2.0. How to make the learning journey from booking to certificate genuinely accessible.

13 min read