CSS forced-colors in Windows High Contrast Mode
The CSS forced-colors media feature detects whether a
user agent has enforced a restricted, user-chosen color palette across
the interface, as seen in Windows High Contrast Mode (now called
Contrast Themes in Windows 11). This article explains how the
forced-colors media query works, why it is critical for web
accessibility, how the browser modifies standard CSS styles under this
mode, and how developers can write targeted CSS rules to ensure custom
user interfaces remain functional and legible.
What is the
forced-colors Media Feature?
The forced-colors media query is defined in the CSS
Media Queries Level 5 specification. It evaluates whether the operating
system or browser is forcing a limited color palette onto the page to
improve visual contrast and readability.
The query accepts two values:
none: The operating system has not imposed a restricted color palette. Web pages render with their standard authored styles.active: A restricted color palette is enforced by the operating system or browser. Author-defined colors are overridden by system-level color choices.
@media (forced-colors: active) {
/* High contrast specific styles go here */
}How Windows High Contrast Mode Interacts with the Browser
When a user enables a Contrast Theme in Windows, the browser enters forced colors mode. To guarantee minimum contrast ratios for people with low vision or photophobia, the browser automatically strips or overrides specific CSS properties:
colorandbackground-colorare mapped to system values (such asCanvasandCanvasText).border-coloris normalized to the system foreground color.box-shadowandtext-shadoware completely removed.fillandstrokeon SVGs may be overridden with system text colors.- Background images set via
background-imageare often hidden unless they are explicitly defined as CSS gradients or content images.
While these automated overrides make plain text readable, they can inadvertently break custom interactive components where visual boundaries or indicators rely on shadows, background colors, or subtle color contrasts.
Common Use Cases for
forced-colors: active
Developers use the @media (forced-colors: active) block
to address interface elements that lose meaning or visibility when the
browser overrides colors.
1. Restoring Lost Visual Boundaries
Modern designs frequently use box-shadow instead of
borders for cards, modals, or form controls. Because forced colors mode
disables shadows, these elements blend into the background. Developers
can use forced-colors: active to apply explicit
borders:
.card {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
@media (forced-colors: active) {
.card {
border: 1px solid CanvasText;
}
}2. Ensuring Transparent Borders for Focus States
A common pattern is using transparent borders on elements in default
states so that adding a border on :focus or
:hover does not cause layout shifting. In forced colors
mode, transparent borders (border: 1px solid transparent)
are rendered as solid system-colored lines. To prevent unexpected
visible borders, use border-color: transparent carefully or
ensure they render properly using system keywords.
3. Preserving SVG Icons
Inline SVGs using custom fills can disappear if the icon's background
and fill both resolve to the same system color. By scoping SVG styles
inside a forced-colors: active block, you can map fills
directly to CSS system keywords:
@media (forced-colors: active) {
.icon {
fill: LinkText;
}
}Working with CSS System Colors
When adapting styles inside forced-colors: active,
hardcoded hex or RGB colors should not be used. Hardcoded values defeat
the purpose of the user's custom high-contrast settings (e.g.,
white-on-black vs. yellow-on-black). Instead, use standard CSS system
color keywords that adapt dynamically to the user's selected theme:
Canvas: Background of the application or document.CanvasText: Main text color on the canvas.LinkText: Text color for unvisited hyperlinks.Highlight: Background color for selected items or text.HighlightText: Text color for selected items.ButtonFace: Background color for buttons.ButtonText: Text color for buttons.Mark: Background color for highlighted text (such as the<mark>tag).
Opting Out with
forced-color-adjust
In rare scenarios, an element must retain its original authored
colors even when forced colors mode is active. Examples include color
pickers, brand identity swatches, or photographic image filters. The
forced-color-adjust property allows developers to exempt
specific elements from browser overrides:
.color-swatch-red {
background-color: #e63946;
forced-color-adjust: none;
}Setting forced-color-adjust: none prevents the browser
from changing the element's colors. This property should be used
sparingly and only on elements where the preservation of true color is
essential to the functionality of the interface.