Skip to content

[Bug]: Text links have no visible focus indicator in forced-colors / Windows High Contrast Mode (all palettes) #176

Description

@stevenpelletier90

Describe the bug

Text links don't show a focus ring in Windows High Contrast Mode. Same on all six palettes.

The inline focus ring in src/scss/_hds-mixins.scss:154 is drawn with four repeating-linear-gradient background layers, and the mixin also sets outline: none.

In forced colors mode the browser drops background images that aren't url() based, and that includes gradients. It's documented on MDN. So the four gradient layers compute to none, and since the outline was turned off too, there's nothing left to draw.

That's also why the icons are fine. The accordion chevron, table sort arrows, error icon and external link arrow all use mask-image: url(...), and url-based images are kept.

Buttons are fine for a different reason. src/scss/base/_focus.scss:23-30 gives them the mask-based ring as well. That rule covers button, input, select, textarea, iframe, [tabindex] and [contenteditable], but not a. So links only have the gradient ring, and it's gone.

This is in HDS, not USWDS.

To Reproduce

  1. Turn on a Windows contrast theme: Settings > Accessibility > Contrast themes > Aquatic. Or in DevTools, Rendering > Emulate CSS media feature forced-colors: active.
  2. Load a page with a .usa-link inside .usa-prose.
  3. Tab to the link.

The link is focused, but nothing appears. What I get:

Element normal forced colors
a.usa-link (prose) ring nothing
a.usa-link--external ring nothing
breadcrumb link ring nothing
bare <a> in prose ring nothing
a[tabindex="0"] ring nothing
a.usa-button ring ring
button.usa-button ring ring

Same on white, light, midtone, dark, blue and black.

Expected behavior

The focus ring should still show in forced colors. WCAG 2.1 SC 2.4.7 Focus Visible, Level AA.

One option, if it's useful. Instead of outline: none, use a transparent outline:

outline: 1px solid transparent;
outline-offset: 1px;

A transparent outline draws nothing normally, so it doesn't change how anything looks today. In forced colors the browser replaces outline-color with a system color, so the ring comes back by itself and you don't need a media query. I tried it on the three broken elements. Focus came back and normal mode looked exactly the same as before:

The prose link focused in forced colors after the transparent outline change, with a visible focus ring

Styling is your call, I just wanted to mention an option that doesn't need a design decision behind it.

Screenshots

Same link, same focus, forced colors off then on.

Normal, ring is there:

Focused prose link in normal mode with a dashed focus ring

Forced colors, nothing:

The same focused prose link in forced colors mode with no focus indicator

Environment:

  • OS: Windows 11 Home, build 26200, using the real Aquatic contrast theme
  • Browser: Chrome 150.0.7871.187
  • HDS Core Version: 0.9.0

Couple of side notes.

The FocusTest stories cover all six palettes in Chromatic, but there's no forced colors mode in .storybook/modes.js, and axe can't check focus visibility. That's probably why this got past.

docs/508.md lists 2.4.7 as Partially Supports because of a USWDS file input issue. Forced colors isn't mentioned either way. Might be worth settling before the v1.0 submission.

I can put together a check for this if you want it. Something that fails the build if a focus ring stops showing up in forced colors, so it can't quietly come back.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions