Skip to Content
Component ExamplesForced Colors

Overview

Windows High Contrast Mode (now called Contrast Themes) overrides author-defined colors with a limited system palette. CSS exposes this via the forced-colors: active media query. In forced colors mode, the browser strips most decorative styling — backgrounds, box-shadows, and background images disappear. What survives: text color, borders, outlines, and SVG currentColor. Designs that rely solely on background color for visual meaning become invisible rectangles. The key defensive pattern is the transparent border trick: borders that are invisible in normal mode but become visible in forced colors.

WCAG Criteria:

Key requirements:

  • Forced colors removes: background-color, box-shadow, background-image, text-shadow
  • Forced colors preserves: border, outline, text color, SVG currentColor, forced-color-adjust: none
  • Use border: 2px solid transparent on interactive elements — invisible normally, visible in forced colors
  • Use outline instead of box-shadow for focus indicators
  • Use currentColor for SVG icons so they adapt to the system color scheme
  • Test with the @media (forced-colors: active) query to add specific overrides using CSS system colors like ButtonText, Canvas, LinkText, Highlight
  • The forced-color-adjust: none property opts an element out of forced colors — use sparingly and only when you provide adequate contrast yourself

Forced Colors Compatibility

Forced Colors Safe Buttons vs. Background-Only Buttons

Inaccessible
<!-- Relies on background-color and box-shadow only --> <button style="background: #2563eb; color: white; border: none; border-radius: 6px;" onfocus="this.style.boxShadow = '0 0 0 3px rgba(37,99,235,0.5)';" onblur="this.style.boxShadow = 'none';"> Primary </button> <button style="background: #64748b; color: white; border: none; border-radius: 6px;" onfocus="this.style.boxShadow = '0 0 0 3px rgba(100,116,139,0.5)';" onblur="this.style.boxShadow = 'none';"> Secondary </button> <button style="background: #dc2626; color: white; border: none; border-radius: 6px;" onfocus="this.style.boxShadow = '0 0 0 3px rgba(220,38,38,0.5)';" onblur="this.style.boxShadow = 'none';"> Delete </button> <!-- In forced colors mode: - background-color is overridden → buttons lose visual distinction - box-shadow is removed → no focus indicator - border: none → no visible boundary at all -->
Live Preview

These buttons rely on background-color for distinction and box-shadow for focus. In forced colors mode, they become borderless, indistinguishable rectangles with no focus ring.

Accessible
<style> .btn:focus-visible { outline: 3px solid #005fcc; outline-offset: 2px; } @media (forced-colors: active) { .btn { border-color: ButtonText; } .btn:focus-visible { outline-color: Highlight; } .btn.danger { border-color: LinkText; } } </style> <!-- Transparent border: invisible normally, visible in forced colors --> <button class="btn" style="background: #2563eb; color: white; border: 2px solid transparent; border-radius: 6px;"> Primary </button> <button class="btn" style="background: #64748b; color: white; border: 2px solid transparent; border-radius: 6px;"> Secondary </button> <button class="btn danger" style="background: #dc2626; color: white; border: 2px solid transparent; border-radius: 6px;"> Delete </button> <!-- In forced colors mode: - transparent borders become visible with system colors - outline focus ring is preserved - CSS system colors (ButtonText, Highlight, LinkText) adapt to the user's chosen contrast theme -->
Live Preview

These buttons use transparent borders (visible in forced colors) and outline for focus. In forced colors mode, borders become visible using system colors.

What’s wrong with the bad example?

  • border: none means there is no border at all — in forced colors mode, the buttons have no visible boundary
  • background-color is overridden by the system palette, so all three buttons look identical — the visual distinction between Primary, Secondary, and Delete is completely lost
  • box-shadow is stripped in forced colors mode, so the focus indicator disappears entirely
  • Keyboard users in high contrast mode cannot tell which button has focus

The transparent border trick:

  • border: 2px solid transparent is invisible in normal mode (transparent blends with the background)
  • In forced colors mode, the browser replaces transparent with the system text color, making the border visible
  • This gives every button a clear visual boundary without changing the normal appearance
  • The @media (forced-colors: active) block can further customize border colors using CSS system colors

What users see in forced colors mode:

VersionAppearance in High Contrast
Bad (border: none, box-shadow focus)Borderless text floating on the system background, no focus ring
Good (transparent border, outline focus)Clear bordered buttons with system-color focus ring

Resources