WHCM and System Colors

There is a ton of prior content discussing Windows High Contrast Mode (WHCM) and web content. The catch is that content covers four (five?) different implementations across more than a decade of support: Internet Explorer, Edge, the other Edge, Edge plus IE aliasing, and hardly anything on Firefox. Which means much of it no longer applies.

The best overview of the current situation is from Microsoft: Styling for Windows high contrast with new standards for forced colors, posted mid-September 2020. As the standards process moves forward and Edge continues to update, expect this overview to be updated (or point to updates).

That post covers the basics of the feature (I do not). Because I want you to try my examples, this is how to activate WHCM:

Please remember that High Contrast Mode is used by some to produce low contrast screens.

The typical contrast of the operating system or the web can be uncomfortable for many people. The most common use case might be someone prone to migraines. High Contrast Mode allows them to create a low contrast palette to help mitigate that.

Low Contrast theme High Contrast #1 theme High Contrast Black theme High Contrast White theme
Four variations on WHCM themes. The low contrast theme (first in this set) is not pre-configured; I created it to reflect what I have seen in use.

Remember as you go down this path that your role as the developer is not to increase the contrast of everything on the screen, but to honor the user settings and system color preferences.

As you read this, I want your primary takeaway to be that you likely will need to do little for standard document pages. If you have some novel custom widgets, then please add and use styles with keywords that correspond to function. If you need to retain some coloring for important contextual reasons, then look at the overrides.

Feature Queries

Since Microsoft introduced WHCM, Internet Explorer had good reason to support a feature query to detect it and allow developers to tweak and override how the styles are applied.

First I want to qualify that if you are using standard HTML, you should not need these. Plain text and native controls adapt just fine. The problems come when you start to introduce custom widgets, ARIA properties, necessary visual flourishes, and so on.

You should only ever use these feature queries to spackle over gaps (found in most libraries / frameworks) or enhance an experience that may be lacking.

Proprietary, or Internet Explorer Only

In Internet Explorer you can use a proprietary feature query to detect if WHCM is active, along with another to detect if the WHCM setting is light on dark, or dark on light. I advise you to only check if it is active (the first from the following set).

@media screen and (-ms-high-contrast: active) {
  /* put your custom styles here */
}
@media screen and (-ms-high-contrast: black-on-white) {
  /* put your custom styles here */
}
@media screen and (-ms-high-contrast: white-on-black) {
  /* put your custom styles here */
}

I identify the six system colors available to you below in the WHCM Proprietary Feature Query Color Mappings section. However, you shouldn’t be too worried about those unless you are fixing broken custom controls. I encourage you to read Greg Whitworth’s overview of how to use -ms-high-contrast well.

Instead you can use this feature query to tweak things like spacing or even disable some unwanted features via -ms-high-contrast-adjust:

@media screen and (-ms-high-contrast: active) {
  selector {
    -ms-high-contrast-adjust: none;
  }
}

If you are still somehow supporting Legacy Edge (Ledgacy), these feature queries and custom properties apply there as well.

Standards Track, or Edge Only

To disambiguate, when I reference Edge here I am talking about ChromiEdge, or the version of Edge built on Chromium. As of this writing, Legacy Edge is nearly gone in the wild and will be wiped from hold-out computers in non-locked-down environments in April 2021.

Sometime in the future I hope to remove the “or Edge Only” from that heading. I hope that the work Edge has done in Chromium gets slurped up to the Chrome engine, copied into Firefox, and somehow maybe even replicated in Safari with a similar macOS-level contrast setting.

Until then, the proposed forced colors mode feature of the CSS Color Adjustment Module Level 1 Working Draft has just the one browser supporting it.

In this case the syntax is easier since either the forced colors mode is on or not.

@media screen and (forced-colors: active) {
  /* put your custom styles here */
}

The following properties are affected:

I was glad to see scrollbar in there given the resurgence of folks making terribly styled scrollbars

As with the proprietary feature, you also have the option to opt out of the color overrides. This is handy in cases where the colors are important to convey something without changing, such as paint, lipstick, or underpants. In those scenarios you would use forced-color-adjust:

@media screen and (forced-colors: active) {
  selector {
    forced-color-adjust: none;
  }
}

Frankenquery’s Monster

Frankenquery is the name of the scientist. Its monster is this:

@media screen and (-ms-high-contrast: active),
  screen and (forced-colors: active) {
    selector {
      -ms-high-contrast-adjust: none;
      forced-color-adjust: none;
    }
}

You could use this to target all the supporting browsers in one block. But be certain your system color keywords work across them all or that you override in the correct order. You may also want more targeted styles if you are trying to replicate native WHCM colors with your custom controls, considering native elements are a bit different between IE11 and Edge.

System Colors

Pulling from system colors means you will generally be leaning on what the user prefers, or at least what they are used to. CSS 2 introduced system font keywords in 1998 (which I wrote about in 2015 when Apple did its own thing), so the notion of using the operating system as a source is not new.

CSS2 System Color Keywords

CSS2 defined 28 keywords which were later carried into CSS Color Module Level 3 System Color Keywords (and then deprecated). From the names, you can guess on the effort to replicate the 3D effects of Microsoft Windows.

In the context of my anecdote, when Windows High Contrast Mode was introduced, using the system color keywords meant no extra work was needed because we had already mapped all the system colors to their native HTML equivalents. Even with the reduced set supported in WHCM, no extra work was needed on our part.

  1. ActiveBorder
  2. ActiveCaption
  3. AppWorkspace
  4. Background
  5. ButtonFace
  6. ButtonHighlight
  7. ButtonShadow
  8. ButtonText
  9. CaptionText
  10. GrayText
  11. Highlight
  12. HighlightText
  13. InactiveBorder
  14. InactiveCaption
  15. InactiveCaptionText
  16. InfoBackground
  17. InfoText
  18. Menu
  19. MenuText
  20. Scrollbar
  21. ThreeDDarkShadow
  22. ThreeDFace
  23. ThreeDHighlight
  24. ThreeDLightShadow
  25. ThreeDShadow
  26. Window
  27. WindowFrame
  28. WindowText

WHCM Proprietary Feature Query Color Mappings

Internet Explorer recognizes a reduced set of these keywords in WHCM. Hyperlinks use the proprietary -ms-hotlight. Handy if using the proprietary feature query in Internet Explorer

  1. ButtonFace
  2. ButtonText
  3. Highlight
  4. HighlightText
  5. Window
  6. WindowText
  7. GrayText
  8. -ms-hotlight

CSS4 System Color Keywords

CSS Color Module Level 4 introduced a different set of system color keywords, dropping the count to 15 and eliminating all the 3D detail.

This reduced set of keywords comes with a warning to ensure you pair background and foreground sets for better contrast.

  1. Canvas
  2. CanvasText
  3. LinkText
  4. VisitedText
  5. ActiveText
  6. ButtonFace
  7. ButtonText
  8. ButtonBorder
  9. Field
  10. FieldText
  11. Highlight
  12. HighlightText
  13. Mark
  14. MarkText
  15. GrayText

While this list may be longer than the set supported in Internet Explorer, bear in mind the colors themselves may be duplicates. For example LinkText and VisitedText use the same color when WHCM is active (which was decided based on user feedback).

Browser Support

Unsurprisingly, each browser is going to have its own take on how best to support WHCM. With a proprietary start that is now moving down the standards track, support will continue to evolve.

Internet Explorer

Internet Explorer was the first to support the proprietary feature query. With some IE11 still in the wild, and given its historic support for WHCM, you may want to double up on your feature query and be careful of relying on background images.

Legacy Edge (Ledgacy)

The original version of Edge carried over the support from Internet Explorer with some adjustments. For example, in a later release it retained background images but added a backplate behind any text set over an image. With the browser nearly gone and Microsoft set to wipe it from hold-out computers in non-locked-down environments in April 2021, you can probably ignore it.

Chromium Edge (Chromiedge)

Microsoft has been building the standards-track support into Edge, and it is working. It also appears Edge still honors the proprietary media query, so you will want to be careful with the cascade when you use both.

Firefox

Firefox supports WHCM, but not the media queries and the media query. Be certain to close and re-open the browser after you enable WHCM, otherwise Firefox does not pick up on it.

8 June 2021: Firefox 89, released May 31, supports the forced-colors media query (thanks to Nicolas in the comments for letting me know). There is more detail in the post Looking fine with Firefox 89 at Mozilla Hacks. Note that the images in this post use Firefox 85, before the feature query support existed.

Chrome

Nope. In fact, there is a bug where if you fail to set the page background, Chrome will use the WHCM window color which is often black. If your text is black (or not set), then your entire page is black.

See the Pen WHCM and Chrome Bug by Adrian Roselli (@aardrian) on CodePen.

Before and after in Chrome showing black on black text then black on white text.
Chrome 88. The left part of the image shows the default display. Activating the button adds a background color to the page, causing Chrome to ignore the assignment from WHCM and working around the bug.

Chrome 89

Chrome 89 supports High Contrast Mode. I can find no release notes that state this, but the change introduced in Edge 79 has seemingly made it into Chrome as of 89. The Chrome 89 beta release notes discuss the addition of forced-colors detection and forced-color-adjust support (Thanks to Šime Vidas for finding that) as well as the Chrome platform status notes.

The test page in Chrome 89 showing it supports the system color scheme. The version screen in Chrome showing it is version 89 and is also honoring system colors.
Chrome 89 demonstrating its support for WHCM.

Examples

I have taken a bunch of the stuff I covered and made some demos. I screen shat (shat is the past tense of shot) them in Firefox, IE11, and Edge. From experience, most WHCM users are not Firefox users, but they are still out there and rely on it working.

Backgrounds

Background images and gradients are treated slightly differently across the three browsers. Firefox sets a text backplate when there is a background image and dumps background gradients; it ignores any feature query overrides. IE11 sets no backplate for either, and dumps both background images and gradients unless you override it. Edge sets a text backplate on a background image, but dumps background gradients, overriding both if you do so in the feature query.

The following embedded pen shows the code, but you can test the debug version of the backgrounds pen.

Side-by-side view of the differences in background display.
Firefox 85, Internet Explorer 11, and Edge 88.

See the Pen WHCM and Backgrounds by Adrian Roselli (@aardrian) on CodePen.

Inline SVGs

Inline SVGs grant you the ability to use CSS at the page level to manipulate their colors. While you can write feature queries into the SVG directly, when calling one inline you may want to handle it in your main stylesheet. In this example I have one SVG that uses currentColor, so it should always inherit from the text. Two more have no colors defined at all, so they default to black, but for one of them I use the WHCM feature queries to set it to use GrayText. The last one has its own colors defined throughout, so is not at risk and needs no overrides.

With Firefox and IE11, currentColor is your friend (along with explicit colors). IE11 honors the feature query (GrayText was just to show it in action). Edge takes it a step further and brings in the text color when no color is defined. Test it yourself in the debug version of this inline SVG pen.

Side-by-side view of the differences in SVG display.
Firefox 85, Internet Explorer 11, and Edge 88.

See the Pen WHCM and SVGs by Adrian Roselli (@aardrian) on CodePen.

SVGs via <img>s

If you have an SVG called via <img> that generally follows a line-art style (icons, for example) then those are most at risk of disappearing completely if their color matches the WHCM window color. Granted, this is true with line-art transparent PNGs, but at least with Edge you can mitigate the effect.

In this example I use filter: drop-shadow() in an effort to create an outline, albeit a faint one, on the first SVG. This is not an ideal solution. The third SVG file has a feature query to override its fill from currentColor to GrayText, and both IE11 and Edge honor it. Give the debug version of SVG <img> pen a test on your own.

Side-by-side view of the differences in SVG display.
Firefox 85, Internet Explorer 11, and Edge 88. IE11 does not recognize the filter property.

See the Pen WHCM and SVG <img>s by Adrian Roselli (@aardrian) on CodePen.

Form Fields

Form fields will also take on a different look, but default form fields will do so in a predictable way. Because WHCM users will expect different field types in different states to look a certain way, it behooves you to know the defaults so you can mimic them in your own work — whether restoring styles you overrode or making a custom control look native.

The set of images below capture disabled, required, and error states. Notice how the placeholder field looks the same as the disabled field in IE11. Or how similar they are in Edge. Or the lack of an error style in Edge. Anyway, test the debug version of this forms pen as you see fit.

Side-by-side view of the differences in native form fields.
Firefox 85, Internet Explorer 11, and Edge 88.
Side-by-side view of the differences in native field error messages.
The default error message from each browser. Firefox 85, Internet Explorer 11, and Edge 88.
Side-by-side view of the differences in native field error states.
The default error state from each browser; note Edge does not distinguish the errored field. Firefox 85, Internet Explorer 11, and Edge 88.

See the Pen WHCM and Form Controls by Adrian Roselli (@aardrian) on CodePen.

Custom Controls

Sadly, it is not uncommon for (terrible) developers to role-up a <div> into a button. While that is rightly offensive, there are also plenty of controls that are not native to HTML, such as the oft misapplied tab. In each of the cases you want to look to the native (HTML or platform) implementation. Try to ensure custom controls give the appropriate visual cues in WHCM after all the fancy gradients and drop shadows and smells are stripped away.

In this pen I compare the styles of a native <button> to a <div>, and offer WHCM styles (proprietary and standards track) to try to reset them to native styles. I even included hover styles appropriate to the browser. You can, of course, test these fake buttons in the debug version of the pen.

Side-by-side view of the differences in native and custom buttons.
Firefox 85, Internet Explorer 11, and Edge 88.

See the Pen WHCM and Custom Buttons by Adrian Roselli (@aardrian) on CodePen.

Collected Examples

I gathered a few samples from above and made screenshots of them in Edge under each of the four themes I showed at the start of this post. Hopefully this reinforces the variety in display, and how using smart defaults will make your job easier. I left the Windows taskbar in there for context.

Demonstrating Low Contrast theme Demonstrating High Contrast #1 theme Demonstrating High Contrast Black theme Demonstrating High Contrast White theme
Examples under each of the themes Low Contrast (custom), High Contrast #1, High Contrast Black, and High Contrast White.

Wrap-up

Your job for WHCM users is to respect their color choices and use them appropriately. Do not override the feature because you may find something ugly. Ugly and usable trumps pretty and unusable every time.

To recap the tips:

References

4 Comments

Reply

From now on, people are undoubtedly going to think something’s wrong with me every time I hear someone use the term “screenshot” when I start laughing uncontrollably. I hope you’re happy.

Great post though, will share far and wide.

In response to James C. Reply

I am just glad I could maybe coin a new term. Thanks!

Reply

It seems that Firefox is now supporting the media query: https://www.mozilla.org/en-US/firefox/89.0/releasenotes/ (See “Web Platform” at the bottom of the release notes)

In response to Nicolas. Reply

Post updated. Thanks!

Leave a Reply to Nicolas Cancel response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>