Skip to main content

High Contrast in FAST

Styling components using forced-colors.#

High contrast mode uses the CSS media feature, forced-colors. When forced-colors is set to active, the user agent will apply a limited color palette to the component.


@media (forced-colors: active) {    :host {        background: ButtonFace;    }}

FAST has a forcedColorsStylesheetBehavior utility function that is used to construct forced-colors in a stylesheet. This function is passed to the withBehavior function from the css tagged template object.


The reason for this behavior is to avoid the runtime cost of applying forced-color style rules when the UA does not match the forced-colors @media query. FAST exposes a behavior that conditionally adds and removes stylesheets based on this media query, so forced-colors' stylesheets can then be conditionally applied where necessary.


export const ComponentStyles = css`    /* ... */ `.withBehaviors(    forcedColorsStylesheetBehavior(        css`            :host {                background: ButtonFace;            }        `    ));

System Color Keyword#

In forced-colors mode, the colors on the component are reduced to a limited color palette chosen by the user. The System Color keywords defined by the CSS Color Module Level 4 specification expose these user-chosen colors.

FAST provides a SystemColors enum to use when setting the color value keywords in a forced-colors stylesheet.


export const ComponentStyles = css`    /* ... */ `.withBehaviors(    forcedColorsStylesheetBehavior(        css`            :host {                background: ${SystemColors.ButtonFace};            }        `    ));

Forced colors and Windows High Contrast themes#

forced-colors works with Windows high contrast mode in Windows, located in Ease of Access within Settings. There are two default themes to test high contrast, High Contrast Black and High Contrast White.

High contrast black theme High contrast white theme

Here is a 1:1 map between the forced-colors keywords and Windows high contrast resource names.

GrayTextDisabled Text
HighlightText HighlightSelected Text
ButtonText ButtonFaceButton Text

Quick demo#

Here is a simple example of adding high contrast to style an accent button. It has selectors for rest, active, hover, focus, and disabled.

Accent button

export const AccentButtonStyles = css`    :host([appearance="accent"]) {        background: ${accentFillRest};        color: ${foregroundOnAccentRest};    }    :host([appearance="accent"]:hover) {        background: ${accentFillHover};    }    :host([appearance="accent"]:active) .control:active {        background: ${accentFillActive};    }    :host([appearance="accent"]) .control:${focusVisible} {        box-shadow: 0 0 0 calc(${focusStrokeWidth} * 1px) inset ${focusStrokeInner};    }    :host([appearance="accent"][disabled]) {        opacity: ${disabledOpacity};        background: ${accentFillRest};    }`

When high contrast is enabled, the system will try to apply the correct color. In the case of this accent button, the system is missing a few things. We do not have a background, rest and hover states are the same, focus is not following the button's focus design, and the disabled state is too dim.

Accent button no forced colors

To fix this, we will pass a forcedColorsStylesheetBehavior object to withBehaviors, using similar selectors, and setting property values with the SystemColors keyword.

export const AccentButtonStyles = css`    /* ... */`.withBehaviors(    forcedColorsStylesheetBehavior(        css`            :host([appearance="accent"]) .control {                forced-color-adjust: none;                background: ${SystemColors.Highlight};                color: ${SystemColors.HighlightText};            }            :host([appearance="accent"]) .control:hover,            :host([appearance="accent"]:active) .control:active {                background: ${SystemColors.HighlightText};                border-color: ${SystemColors.Highlight};                color: ${SystemColors.Highlight};            }            :host([appearance="accent"]) .control:${focusVisible} {                border-color: ${SystemColors.ButtonText};                box-shadow: 0 0 0 2px ${SystemColors.HighlightText} inset;            }            :host([appearance="accent"][disabled]),            :host([appearance="accent"][disabled]) .control,            :host([appearance="accent"][disabled]) .control:hover {                background: ${SystemColors.ButtonFace};                border-color: ${SystemColors.GrayText};                color: ${SystemColors.GrayText};                opacity: 1;            }        `    ));

After adding forced-colors and applying SystemColors keywords, the accent button now uses Highlight as a background for its rest state. On the hover and active states, the background and color from the rest state are swapped. A double border treatment is applied when in the focus state, and the disabled has opacity set to 1 and uses the disabled color, GrayText, for color on the border and content.

Accent button forced colors


forced-color-adjust, controls whether the UA system theme color override, should be applied to an element and its descendants. The example is set to none, because we are overriding to remove the backplate on the text content in the control, that the UA sets on text elements.

Further resources#

Color contrast comparison chart

To help determine whether a pair of high contrast colors will meet a color luminosity contrast ratio of at least 10:1, this table uses the high contrast theme color resource names you see in Windows Ease of Access.

How to read this table:

  • YES - indicates that it is safe to assume this pair of colors will meet high contrast requirements, even in custom themes.
  • YES* - indicates that this specific pair of colors meets the high contrast requirements in both High Contrast Black and High Contrast White themes.
  • NO - indicates that you should never use this pair of colors as they do not meet high contrast requirements in High Contrast Black and High Contrast White themes.
TextHyperlinkDisabled TextSelected Text (Foreground)Selected Text (Background)Button Text (Foreground)Button Text (Background)Background
Selected Text (Foreground)NOYES*YES* NOYESYES*NONO
Selected Text (Background)NONONOYESNONOYES*YES*
Button Text (Foreground)NONONOYES*NONOYESYES

Microsoft Edge blog#

Microsoft Edge blog has excellent and in-depth information on styling for Windows high contrast using forced-colors. Styling for Windows high contrast with new standards for forced colors