Skip to content

Wait out the theme transition before auditing contrast - #42

Merged
michaeljolley merged 1 commit into
mainfrom
dev/mjolley/fix-row-heading-contrast
Aug 7, 2026
Merged

Wait out the theme transition before auditing contrast#42
michaeljolley merged 1 commit into
mainfrom
dev/mjolley/fix-row-heading-contrast

Conversation

@michaeljolley

Copy link
Copy Markdown
Collaborator

The Accessibility and layout job has been failing at random on color-contrast, most recently on PR #40 where the pull_request run failed and the push run for the same commit passed. Same shape as an unexplained failure back in July.

It reproduces with the CPU throttled 8x. One run in eight, and axe hands over the answer:

color-contrast  fgColor #1b1a18  bgColor #15171a  ratio 1.03  expected 3:1

#1b1a18 is bbb-light's --fg. #15171a is bbb-dark's --bg. That is the foreground of the theme being left measured against the background of the theme being arrived at, on text that has never rendered that way for anyone.

Why

Setting data-theme is instant. The colours it implies are not, because app.css transitions color and background-color on body. reducedMotion: 'reduce' collapses that to .01ms, which is a duration and not an absence, so the swap still has to wait for a frame before anything reads the new colour. On an unloaded machine that frame is immediate and the old waitForTimeout(50) covered it. On a loaded CI runner it is not, and the sleep covered nothing.

Both failures landed on the first few headings of a block, which is just what axe reaches first.

The July note in this file had looked at the transition and cleared it, on the reducedMotion reasoning above. That was the wrong conclusion, so it is rewritten with what actually happened and how to reproduce it.

What changed

Nothing in the site. scripts/a11y.mjs only.

  • The theme swap waits for the transitions it starts, by their own promises, two frames after the attribute is set. Animations are deliberately left out, since a looping one never finishes and would hang the gate.
  • Then it proves it took. body is color: var(--fg), so body's computed colour and the applied theme's --fg have to agree before an audit runs. A mismatch reports which two disagree instead of surfacing as a mystery contrast violation.
  • Violations print the data axe already had. This gate has now twice produced a finding nobody could act on while the explanation sat in the results object getting dropped on the floor.

Testing

16 throttled rounds against the same setup that failed on round six of eight, all clean. pnpm test at 391 passing.

The a11y gate has been failing at random on contrast, twice now, and both times
on the first few headings of a block with nothing wrong with them. Reproduced by
throttling the CPU 8x: one run in eight, axe reporting fgColor #1b1a18 against
bgColor #15171a, the foreground of the theme being left on the background of the
theme being arrived at.

Setting data-theme is instant but the colours it implies are not, because app.css
transitions color and background-color. reducedMotion 'reduce' collapses that to
.01ms, which is a duration and not an absence, so the swap still waits on a frame
before anything reads the new colour. On an unloaded machine the old 50ms sleep
covered that frame. On a loaded runner it covered nothing.

So wait for the thing itself. Two frames to get the change through style, layout
and paint, then the transitions it started, awaited by their own promises, with
animations left out because a looping one never finishes. Then prove it: body is
color: var(--fg), so body's computed colour and the theme's --fg have to agree
before the audit runs, and if they ever do not that is what gets reported.

Violations now print the data axe already had, the two colours and the ratio, so
the next one of these is a diagnosis instead of a selector and a shrug. The note
about the July failure is rewritten, since it had cleared the transition and the
transition did it.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f5e5a689-2285-4421-b2b5-b348df97b055
@michaeljolley
michaeljolley merged commit a24ec53 into main Aug 7, 2026
9 checks passed
@michaeljolley
michaeljolley deleted the dev/mjolley/fix-row-heading-contrast branch August 7, 2026 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant