For a meaningful population of low-vision users, an OS-level forced-colors mode isn't optional — it's how they make interfaces perceivable at all. Understanding what it overrides, and how to work with it deliberately, is essential for genuinely inclusive CSS.
1Understanding The Scope Of The Override
Forced-colors mode is a genuine, system-level color override, not a visual theme layered on top of a site's existing design. When active, the browser typically replaces most author-declared colors — background-color, color, border-color — with a small palette the user has explicitly configured in their operating system settings, chosen specifically because it provides them with sufficient perceivable contrast.
What's generally *not* overridden is layout: padding, margin, flex/grid positioning, and overall structure remain as authored. This distinction matters practically — a component's spatial design should survive forced-colors mode largely intact, while its color choices should be expected to be replaced, meaning any design relying on a *specific* color (not just sufficient contrast, but a specific hue) for meaning is fundamentally incompatible with this mode.
2Detecting The Mode For Targeted Adjustments
@media (forced-colors: active) detects whether this override is currently engaged, letting you write CSS specifically for that context without affecting normal rendering otherwise. A common, practical use: a purely decorative background image behind text (which forced-colors mode generally doesn't remove, since it's not a 'color' in the same sense) could obscure text that now relies on the forced text/background color pairing for legibility — inside a forced-colors block, you might disable that background image or force a solid background instead.
The forced-color-adjust: none property is a related, narrower escape hatch — it opts a specific element back out of the automatic color override entirely, useful for cases like a logo or brand mark where the specific colors genuinely need to be preserved regardless of the user's forced-colors configuration, though it should be used sparingly and deliberately, not as a way to broadly resist the accessibility feature.
3CSS System Colors: Cooperating Instead Of Resisting
Rather than treating forced-colors mode purely as something to detect and 'fix around', CSS system color keywords let a component actively cooperate with it: Canvas and CanvasText resolve to the user's chosen page background and text colors respectively; ButtonFace, ButtonText, and ButtonBorder resolve to their button-appropriate equivalents; LinkText and Highlight cover links and selection. These keywords dynamically resolve to whatever specific palette that individual user has configured — using them means a component correctly adapts to any user's particular high-contrast preference, rather than presenting one fixed appearance that might not match.
This reframes forced-colors design from 'defensive damage control' to 'an intentional, cooperative rendering mode' — a well-built component uses system colors deliberately inside its forced-colors block, producing an experience that's genuinely tailored to that specific user's configured needs, rather than merely tolerating an override imposed on it.
4Step-by-Step Breakdown
When The OS Overrides Your Colors Entirely. Windows High Contrast Mode (and similar OS-level forced-colors modes) doesn't apply a theme on top of your CSS — it replaces your chosen colors with a small, user-configured palette entirely, for users who need extremely high contrast to perceive content at all. Designing for this mode means understanding what survives the override and what doesn't.
What Forced Colors Mode Actually Does. When active, forced-colors mode overrides most author-specified colors (background, text, border colors) with a small set of user-chosen system colors, while generally preserving layout, spacing, and non-color styling — your background: #f8fafc might be silently replaced with the user's chosen system background color, regardless of what you wrote.
What Forced Colors Mode Changes. When forced-colors mode is active, what typically happens to an element's declared background-color?
- →It renders exactly as declared, completely unaffected
- →It's typically overridden and replaced with one of the user's small set of chosen system colors, regardless of the original declared value
- →The background is removed entirely, leaving the element fully transparent
Detecting It With @media (forced-colors: active). @media (forced-colors: active) lets you write specific CSS scoped to when this mode is engaged — useful for adjustments that only make sense in that context, like ensuring a purely decorative background image (which forced-colors typically doesn't touch) doesn't obscure content that now relies on the forced text/background color pairing for legibility.
Detecting Forced Colors Mode. What's the purpose of the @media (forced-colors: active) media query?
- →It disables forced-colors mode for the page
- →It lets you write specific CSS adjustments that only apply when forced-colors mode is actually active
- →It has no practical use in real development
CSS System Colors: Designing With The User's Own Palette. Rather than fighting the override, CSS provides keyword system colors (Canvas, CanvasText, LinkText, ButtonFace, Highlight) that resolve to whatever the user's actual forced-colors palette currently is — using these deliberately, instead of your normal design tokens, inside a forced-colors block lets you cooperate with the override rather than working against it.
Using CSS System Colors. Why would a component deliberately use the ButtonFace and ButtonText system color keywords inside a forced-colors media query, instead of its normal design tokens?
- →Purely for shorter, more concise code
- →These keywords resolve dynamically to the user's actual chosen system colors, letting the component cooperate correctly with whatever specific high-contrast palette that user has configured
- →There's no functional difference from using the normal design tokens
High Contrast Mode Understood. You now understand exactly what forced-colors mode overrides and preserves, how to detect and scope adjustments to it with @media (forced-colors: active), and how to use CSS system color keywords to cooperate with the user's own configured high-contrast palette rather than fighting against it.
Keep A Button Visible Without Relying On Color Alone. A visible border ensures the button stays perceivable even in forced-colors/high-contrast modes that strip background colors.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Forced-Colors Mode Serves A Genuine, Distinct Population From Standard Contrast Ratio Compliance
Users who rely on forced-colors mode often need contrast beyond what a well-designed default theme provides, or need a specific, personally-configured palette regardless of how good the default is — this mode serves a real, additional accessibility need that standard WCAG contrast compliance alone doesn't fully address.
2Never Use forced-color-adjust: none Broadly To Simply Preserve A Brand's Default Color Scheme
This property should be reserved for narrow, genuinely justified cases (like a logo needing specific brand colors) — using it broadly to opt an entire interface out of forced-colors mode defeats the purpose of the accessibility feature for the users who depend on it.
SEO Implications
- 1
Forced-Colors Compatibility Testing Catches A Distinct Class Of Issues Standard Contrast Audits Miss
A site can pass every standard WCAG contrast check on its default theme while still rendering broken or illegible under forced-colors mode if it relies on background images, gradients, or non-standard rendering that the override doesn't handle gracefully — this is worth testing as its own distinct audit category.
- 2
Supporting Forced-Colors Mode Well Reduces Accessibility Complaint Risk From A Specific, Identifiable User Population
Windows High Contrast Mode users are a real, identifiable, and often vocal accessibility community — poor support here is a common, specific source of accessibility feedback and complaints.
Best Practices
Test Your Site With Forced-Colors Mode Actually Enabled, Not Just By Reading The CSS
The only reliable way to know how a page actually renders under this override is testing with the real OS-level setting active, since the override's exact behavior can have subtleties not obvious from CSS alone.
Reserve forced-color-adjust: none For Narrow, Specifically-Justified Cases Like Logos
Using it broadly undermines the accessibility feature for the users who depend on it — the default, cooperative behavior (letting the override apply, adjusting with system colors where needed) should be the norm, not the exception.
Frequent Bugs
Text becomes illegible against a background image when a user enables forced-colors mode.
Add a @media (forced-colors: active) rule disabling the background image or forcing a solid Canvas background, since forced-colors mode doesn't automatically account for background images the way it does solid colors.
A component's meaning-carrying color (like a red 'error' indicator) becomes indistinguishable from other elements under forced-colors mode.
Ensure meaning isn't conveyed by color alone — pair it with an icon, text label, or border style change that survives the forced-colors override.
Real-World Examples
A Forced-Colors-Cooperative Button Component
A design system's button component explicitly using CSS system colors within a forced-colors media query, ensuring it renders correctly and cooperatively for any user's specific high-contrast configuration.
@media (forced-colors: active) {
.button {
background: ButtonFace;
color: ButtonText;
border: 1px solid ButtonText;
}
.button:focus-visible {
outline: 2px solid Highlight;
}
}