Supporting CSS prefers-contrast

🕑3 minute readJames IvesJames Ives

The level 5 CSS Media Query specifications include a number of system level preferences that you can access within your web applications. The ones which have been widely adopted so far are prefers-color-scheme and prefers-reduced-motion. There is another coming soon however which is worth talking about, and that’s prefers-contrast. In this post we’ll explore this option and how you can prepare to utilize it to better support and respect user preferences.

Contrast at a Glance

Contrast ratio is the ratio between the maximum and minimum brightness, or in other words, the ratio between the brightest white and the darkest black. The WCAG (Web Content Accessability Guidelines) recommend a minimum contrast ratio of 4.5:1 (with large text recommended at 3:1 or higher) which is a great starting point that covers a wide variety of users. So why do we need this media query if we’re meeting a certain contrast ratio already? It’s better to think of those guidelines as a minimum requirement and not as a one size fits all solution. Simply put some users have a preference in regards to contrast for a variety of different reasons and we should respect that election and provide it where we can. Using the prefers-contrast media query you can determine if a user has made those choices and tailor your application design around it.

One example where a higher contrast may be preffered is cataracts. The following quote is taken from webaim.org who do a good job at describing cataracts along with a number of other vision related needs:

Individuals with cataracts have areas of opacity in the lens of their eyes, which creates a blurred or hazy effect, especially in bright light. Text may be difficult to distinguish from the background. High contrast is especially important for people with advanced cataracts.

Using the Media Query

Using prefers-contrast is pretty straight forward and works like any other CSS media query. The available options include more, less, and no-preference which represents the default. The more value indicates that a user would like to have more contrast, where as less indicates the opposite.

img {
  // Fallbacks work the same way as no-preference.
  filter: contrast(1);
}

@media (prefers-contrast: more) {
  img {
    filter: contrast(1.5);
  }
}

@media (prefers-contrast: less) {
  img  {
    filter: contrast(0.5);
  }
}

You can combine these options with other media queries such as prefers-color-scheme to better shape your applications towards a variety of different users based on their preferences. In the example below I’ve made individual adjustments to the more preference depending on the color scheme the user prefers.

@media (prefers-color-scheme: dark) {
  // dark mode styles
}

@media (prefers-color-scheme: dark) and (prefers-contrast: more) {
  // dark mode styles with more contrast
}

@media (prefers-color-scheme: light) {
  // light mode styles
}

@media (prefers-color-scheme: light) and (prefers-contrast: more) {
  // light mode styles with more contrast
}

Like other media queries these can also be referenced using JavaScript via the window object. If more|less|no-preference all return matches: false you can safely assume the users browser does not have support for this media query yet.

window.matchMedia('(prefers-contrast: more)')
// > MediaQueryList {media: "(prefers-contrast: more)", matches: true, onchange: null, addListener: function, removeListener: function, …}

window.matchMedia('(prefers-contrast: more)').matches
// true

The following example provides insight into your preferences. The animations will stop if you prefer reduced motion, and the contrast will increase or decrease based on what you’ve specified so long as it’s supported by your browser. Deja vu?

Matrix Cat MonteMatrix Cat Pica

Browser Support ⏰

At the time of writing this post this media query isn’t widely available across different browsers. Currently only Safari has full support and Firefox has the option implemented behind a flag. There’s however been communication from Edge that Chromium will soon follow, so it’s only a matter of time before this gets wider support. If you’d like to give this a shot in Safari you can enable this setting via the System Preferences > Accessibility menu on a MacOS device that has at least Safari 14.1 installed.

System Preferences

At an operating system level Microsoft has supported high and low contrast themes in Windows for as long as I can remember. They even had a Microsoft CSS extension that supported detection of these modes for a while that worked very similarly to prefers-contrast. It was however experimental and has been deprecated for quite some time.

Closing Notes

Everything in this post is subject to change, the intention of this post was to help you prepare for this feature so you can begin plotting how you’d like to support this, if at all. I’m curious to know how you’ll utilize prefers-contrast in your application and what your plans are for it when it becomes more mainstream. if you have any questions or comments please reach out via Twitter or LinkedIn.