fix(a11y): distinct landmark names, a working skip link, and no unnamed banner landmark #169

Sammanfogat
supernaut sammanfogade 3 incheckningar från fix/nav-a11y-semantics in i main 2026-08-02 19:29:24 +00:00
Ägare

Closes #157, closes #158, closes #168.

Three accessibility defects in the navigation landmarks and the skip link.

#157 — two <nav> landmarks were both exposed as "Bitborg", so a screen reader's landmark list
offered the same name twice with no way to tell them apart. Renames them in both dictionaries, and
fixes two smaller problems in the same strings: landmark names that repeated their own role
("Main Navigation navigation"), and nav.legal.label, which was the English word "Legal" sitting in
the Swedish dictionary as visible footer copy.

Key English Swedish
nav.app.label Bitborg at git.gitborg.se Bitborg på git.gitborg.se
nav.main.label Pages Sidor
nav.secondary.label Account Konto
nav.legal.label Legal Villkor

The full landmark set was checked in both languages, not just the two named ones — all distinct, and
nav.secondary.label does not collide with the account panel's own "Account links" landmark.

#158 — <main id="main-content"> had no tabindex="-1", so WebKit scrolled without moving
focus and the next Tab walked straight back into the header. That is every browser on iOS. Verified
that the outline behaviour is unchanged for mouse users: the only global focus rule is
:focus-visible, which a mouse click on a tabindex="-1" element does not match.

#168 — the announcement banner rendered a <nav> with no accessible name, so it appeared in the
landmark list as a bare "navigation". Rendered as a <div> instead of named: a single promotional
link is not a navigation region. Styling keys off the .banner class, not the element.

Verification

pnpm lint, pnpm check (0 errors), pnpm lang-check and pnpm test (206 passing) all clean.
src/lib/nav.test.ts untouched.

Not covered

#158's acceptance is stated in terms of real Safari behaviour; the mechanism and the CSS were
verified statically, but no device test was run.

Closes #157, closes #158, closes #168. Three accessibility defects in the navigation landmarks and the skip link. **#157** — two `<nav>` landmarks were both exposed as "Bitborg", so a screen reader's landmark list offered the same name twice with no way to tell them apart. Renames them in both dictionaries, and fixes two smaller problems in the same strings: landmark names that repeated their own role ("Main Navigation navigation"), and `nav.legal.label`, which was the English word "Legal" sitting in the Swedish dictionary as visible footer copy. | Key | English | Swedish | | --- | --- | --- | | `nav.app.label` | Bitborg at git.gitborg.se | Bitborg på git.gitborg.se | | `nav.main.label` | Pages | Sidor | | `nav.secondary.label` | Account | Konto | | `nav.legal.label` | Legal | Villkor | The full landmark set was checked in both languages, not just the two named ones — all distinct, and `nav.secondary.label` does not collide with the account panel's own "Account links" landmark. **#158** — `<main id="main-content">` had no `tabindex="-1"`, so WebKit scrolled without moving focus and the next Tab walked straight back into the header. That is every browser on iOS. Verified that the outline behaviour is unchanged for mouse users: the only global focus rule is `:focus-visible`, which a mouse click on a `tabindex="-1"` element does not match. **#168** — the announcement banner rendered a `<nav>` with no accessible name, so it appeared in the landmark list as a bare "navigation". Rendered as a `<div>` instead of named: a single promotional link is not a navigation region. Styling keys off the `.banner` class, not the element. ### Verification `pnpm lint`, `pnpm check` (0 errors), `pnpm lang-check` and `pnpm test` (206 passing) all clean. `src/lib/nav.test.ts` untouched. ### Not covered `#158`'s acceptance is stated in terms of real Safari behaviour; the mechanism and the CSS were verified statically, but no device test was run.
supernaut lade till 3 incheckningar 2026-08-02 15:53:17 +00:00
The header's "Open Gitborg" link and the footer's service column were both
labelled "Gitborg", so a screen reader's landmark list offered "Gitborg
navigation" twice with no way to tell them apart (WCAG 1.3.1). The header one
now carries the hostname, which is the one case docs/content-style.md allows it
— the website and the application have to be told apart. The visible footer
heading keeps the bare brand name.

Two smaller faults in the same set of strings:

- nav.main.label and nav.secondary.label repeated their own role, announced as
  "Main Navigation navigation". They now name their contents instead.
- nav.legal.label was the English word "Legal" in the Swedish dictionary, where
  footer.astro renders it as visible copy.

Closes #157.
<main id="main-content"> was not focusable, and WebKit does not move focus to a
fragment target that cannot take it: it scrolled, left focus in the header, and
the next Tab walked straight back into the navigation. On iOS every browser is
WebKit, so the bypass-blocks mechanism bypassed nothing — past roughly fourteen
tab stops of chrome.

tabindex="-1" makes <main> a valid focus target without adding a tab stop. The
comment says why, so it does not read as removable. Mouse users see no change:
the outline is bound to :focus-visible (src/style/base.scss), which a click does
not match.

Closes #158.
fix(a11y): stop the announcement banner being an unnamed landmark
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m25s
2fc3d70c91
The banner rendered a nav, so it appeared in the landmark list as a bare
'navigation' with nothing to identify it — the same defect #157 fixed for the
two landmarks that shared a name.

Rendered as a div instead of named, because a nav is a landmark and a single
promotional link is not a navigation region. Styling keys off the .banner
class, not the element, so nothing else changes.

Closes #168
supernaut tvångsskickade fix/nav-a11y-semantics från 2fc3d70c91
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m25s
till 2272837e13
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m18s
2026-08-02 19:25:29 +00:00
Jämför
supernaut sammanfogade incheckning 6a94c84832 till main 2026-08-02 19:29:24 +00:00
supernaut tog bort grenen fix/nav-a11y-semantics 2026-08-02 19:29:24 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-web!169
Ingen beskrivning angiven.