From fd86d968a4bc3bfa1d21e8e5f64c99726228e476 Mon Sep 17 00:00:00 2001 From: Till JS Date: Fri, 8 May 2026 18:24:33 +0200 Subject: [PATCH] Phase 9h: A11y-Pass MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- apps/web/src/app.css | 52 +++++++++++++++++++ apps/web/src/lib/components/Header.svelte | 4 +- apps/web/src/lib/components/ToastStack.svelte | 13 ++++- apps/web/src/lib/i18n/de.ts | 4 ++ apps/web/src/lib/i18n/en.ts | 4 ++ apps/web/src/routes/+layout.svelte | 13 ++++- apps/web/src/routes/decks/+page.svelte | 2 +- apps/web/src/routes/decks/[id]/+page.svelte | 2 +- 8 files changed, 87 insertions(+), 7 deletions(-) diff --git a/apps/web/src/app.css b/apps/web/src/app.css index e81a46b..b3f7ed9 100644 --- a/apps/web/src/app.css +++ b/apps/web/src/app.css @@ -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) { diff --git a/apps/web/src/lib/components/Header.svelte b/apps/web/src/lib/components/Header.svelte index f87b008..59a3045 100644 --- a/apps/web/src/lib/components/Header.svelte +++ b/apps/web/src/lib/components/Header.svelte @@ -18,7 +18,7 @@ {t('app.name')} -