Phase 9h: A11y-Pass

Globaler :focus-visible-Outline (var(--color-primary), 2px) — Tailwind 4
strippt die Browser-Defaults, ohne Fokus-Ring sind Tastatur-Nutzer blind.
.sr-only-Utility (Standard-Rezept) und .skip-link in app.css. prefers-
reduced-motion: schaltet alle Transitions/Animationen auf 0.01ms.

Layout: Skip-Link "Zum Inhalt springen" → #main, main bekommt tabindex="-1"
und id, html-lang wird via $effect reaktiv mit i18n.current synchronisiert
(Initial-SSR rendert "de", Browser zieht nach).

Header: nav-aria-label aus i18n (common.main_nav), Locale-Switcher-Label
aus common.language_switcher. ToastStack: role=region + aria-live=polite,
einzelne Toasts role=alert (error) bzw. status (success/warning), Schließen-
Button-Label i18n-konform.

Hover-only Delete-Buttons (Decks-Liste, Deck-Detail-Karten) bekommen
focus-visible:opacity-100 — bisher waren sie für Tastatur-Nutzer
unsichtbar. opacity-0 statt hidden, damit Tab-Order intakt bleibt.

svelte-check 379 files 0 errors, prod-Build sauber.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-05-08 18:24:33 +02:00
parent c25c1d0dc4
commit fd86d968a4
8 changed files with 87 additions and 7 deletions

View file

@ -26,6 +26,58 @@
body {
min-height: 100dvh;
}
/* Sichtbarer Fokus-Ring für Tastatur-Nutzer. Tailwind 4 strippt
die Browser-Defaults; wir setzen einen expliziten Outline.
Nur :focus-visible, damit Maus-Klicks visuell sauber bleiben. */
:focus-visible {
outline: 2px solid var(--color-primary);
outline-offset: 2px;
border-radius: 2px;
}
/* Screen-Reader-only Utility. Wird im Study-View genutzt, um die
Prompt-/Answer-Regionen unsichtbar zu betiteln. */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
/* Skip-Link: versteckt bis Fokus, dann sprung zur Main-Region. */
.skip-link {
position: absolute;
top: 0;
left: 0;
padding: 0.5rem 0.75rem;
background: var(--color-primary);
color: var(--color-primary-fg);
z-index: 50;
transform: translateY(-200%);
transition: transform 0.15s;
}
.skip-link:focus {
transform: translateY(0);
}
}
/* Reduce-Motion-Respekt: Animationen + Transitions ausschalten,
wenn der User das im OS so eingestellt hat. */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
}
@media (prefers-color-scheme: dark) {