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
- Turn on a Windows contrast theme: Settings > Accessibility > Contrast themes > Aquatic. Or in DevTools, Rendering > Emulate CSS media feature forced-colors: active.
- Load a page with a
.usa-link inside .usa-prose.
- 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:
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:
Forced colors, nothing:
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.
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:154is drawn with fourrepeating-linear-gradientbackground layers, and the mixin also setsoutline: 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 tonone, 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-30gives them the mask-based ring as well. That rule coversbutton,input,select,textarea,iframe,[tabindex]and[contenteditable], but nota. So links only have the gradient ring, and it's gone.This is in HDS, not USWDS.
To Reproduce
.usa-linkinside.usa-prose.The link is focused, but nothing appears. What I get:
a.usa-link(prose)a.usa-link--external<a>in prosea[tabindex="0"]a.usa-buttonbutton.usa-buttonSame 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:A transparent outline draws nothing normally, so it doesn't change how anything looks today. In forced colors the browser replaces
outline-colorwith 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: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:
Forced colors, nothing:
Environment:
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.mdlists 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.