Skip to content

A hairline that vanished in high contrast

Every line in the frame survived forced colours except one, and the difference was how it was painted.

View as Markdown

The site’s whole visual identity is hairlines: rails down both edges, a seam between bands, small rotated squares at the corners, a hatched divider. In Windows High Contrast Mode, one of them disappeared and the rest were fine.

Why only one

Forced colours replaces a fixed set of properties with system colours: color, background-color, border-color, outline-color, and a few more. A border survives because border-color is replaced with CanvasText. A CSS gradient survives because background-image is not in the list.

Every line in the frame was a border or a gradient — except the seam between bands, which was a one-pixel div whose only paint was background-color. Forced colours replaced it with Canvas, the same colour as the page behind it. It did not fade; it became the background.

The fix, and the thing that nearly made it useless

Naming a system colour is the whole fix:

html
<span class="h:[1px] bg-color:gray-500 bg-color:[CanvasText]@forced-colors"></span>

But media queries carry no specificity. Both rules are a single class, so whichever the stylesheet emits last wins. Had bg-color:gray-500 come after the forced-colors block, the fix would have been a no-op that still passed every test — the class would be present, the CSS would exist, and the line would still vanish.

It was worth checking rather than assuming. In the built stylesheet the base utility sits at byte 102188 and the forced-colors rule at 126668, so the system colour wins.

What we did not fix

The footer carries a small decorative flourish, also painted with a background, also erased in forced colours. We left it. The rule that decided it: match the design intent, not the pixel. The seam is full strength and meant to be seen, so its erasure is a regression. The flourish is a deliberate 28% wisp, and repainting it CanvasText would not restore the intent — it would invert it, turning a whisper into a crisp rule that reads as structure the design never claimed.

Since then

The background-painted seam is gone. Aligning the corner nodes forced a stricter rule — every frame row draws the boundary as a border on its own bottom edge — and a border was the only shape that put the line and the node on the same pixel. So the fix described above is now redundant twice over: a border is already replaced with CanvasText, and the seam names it anyway. The reasoning survives the mechanism. A line’s paint decides whether it exists in forced colours, and the property you reach for is not a free choice.