Barrierefreiheit (A11y)
WCAG 2.1 AA Konformität ist das Ziel. Diese Seite dokumentiert die A11y-Strategien, -Tools und -Anforderungen des Systems.
A11y-Utilities
Wiederverwendbare Scripts unter src/components/a11y/:
utils.ts
Basis-Helfer: typisierte Query-Selectors (qsa, qs), uid() für einzigartige IDs, ensureId() für Auto-IDs, getFocusable() für alle fokussierbaren Elemente, Keyboard-Event-Helfer (isEnter, isEscape, isTab, isArrowDown etc.), prefersReducedMotion().
focus-trap.ts
Focus-Trap für modale Elemente (Dialog, Mobile Nav). createFocusTrap(container) gibt activate() und deactivate() zurück. Tab/Shift+Tab cycled durch fokussierbare Elemente innerhalb des Containers.
live-region.ts
Screen-Reader Announcements: announce('5 Ergebnisse gefunden') erstellt eine aria-live Region und liest den Text vor. Wichtig für dynamische Inhalts-Updates (Galerie-Wechsel, Filter-Ergebnisse).
aria-toggle.ts
Universelles Toggle für aria-expanded/aria-hidden Paare. Nutzt data-toggle-trigger und data-toggle-target Attribute. Keyboard: Enter/Space zum Toggeln, Escape zum Schliessen.
scroll-reveal.ts
IntersectionObserver für Scroll-Animationen. Bei prefers-reduced-motion: reduce werden alle Elemente sofort sichtbar (keine Animation). Elemente sind für Screen-Reader immer lesbar.
WCAG 2.1 AA Anforderungen
1. Wahrnehmbar
- 1.1 Textalternativen: Alle Bilder haben Alt-Texte. Dekorative Bilder:
alt="" - 1.3 Anpassbar: Semantisches HTML (
<nav>,<main>,<article>). Korrekte Heading-Hierarchie - 1.4.3 Kontrast: Mindestens 4.5:1 für Text, 3:1 für großen Text. Brand-Tokens erfüllen dies
- 1.4.4 Textgroesse: Fluid Typography mit
clamp()— skaliert mit Viewport - 1.4.10 Reflow: Kein horizontales Scrollen bis 320px Viewport. Content-Grid handhabt das
- 1.4.11 Non-text Contrast: Focus-Ringe, Buttons, Borders haben 3:1 Kontrast
2. Bedienbar
- 2.1.1 Tastatur: Alle Funktionen sind per Tastatur bedienbar. Components implementieren Arrow-Keys, Enter, Space, Escape
- 2.1.2 Keine Tastaturfalle: Focus-Traps (Modal, Mobile Nav) haben immer einen Ausweg (Escape)
- 2.4.1 Skip Link: "Zum Inhalt springen" Link am Seitenanfang (in Layout.astro)
- 2.4.3 Fokusreihenfolge: Tab-Reihenfolge entspricht der visuellen Reihenfolge
- 2.4.7 Fokus sichtbar:
:focus-visibleRing auf allen interaktiven Elementen (in reset.css) - 2.3.1 Keine Blitze: Keine blinkenden Elemente. Animationen respektieren
prefers-reduced-motion
3. Verstaendlich
- 3.1.1 Sprache:
<html lang="de">auf jeder Seite - 3.2.1 Bei Fokus: Kein Kontextwechsel bei Fokus-Erhalt
- 3.3.1 Fehlererkennung: Input-Component zeigt Fehler mit
aria-describedby - 3.3.2 Labels: Jedes Formularfeld hat ein sichtbares Label
4. Robust
- 4.1.1 Parsing: Valides HTML. Keine doppelten IDs (uid() generiert einzigartige)
- 4.1.2 Name, Rolle, Wert: ARIA-Attribute auf allen interaktiven Components (
role,aria-expanded,aria-selected,aria-controls)
A11y pro Component
| Component | ARIA Pattern | Keyboard | Besonderheiten |
|---|---|---|---|
| Accordion | <details> + <summary> | Enter/Space | Native HTML, kein ARIA nötig |
| Tabs | Roving Tabindex | Arrow Left/Right, Home/End | role="tablist", aria-selected |
| Dialog | Native <dialog> | Escape schließt, Tab-Trap | Focus-Trap, Scroll-Lock, Focus-Restore |
| Navigation | <nav aria-label> | Escape schließt Mobile | Focus-Trap im Mobile-Menu, aria-expanded |
| Gallery | role="list" + <dialog> | Arrow Left/Right in Lightbox | Live-Region für Bildwechsel-Announcements |
| Card | Clickable Card Pattern | Tab + Enter auf Link | Focus-Ring auf <article>, nicht auf Link |
| Button | <button> / <a> | Enter/Space | :focus-visible Ring, Loading-State mit aria-busy |
| Input | Label + aria-describedby | Standard-Form-Tab | Error-Messages verknüpft via ID |
Testen
Automatisiert
- axe-core: Im Test-Setup integriert (
pnpm test) - Lighthouse: Chrome DevTools → Lighthouse → Accessibility
- WAVE: Browser-Extension für Seiten-Audits
Manuell
- Tastatur-Test: Seite nur mit Tab, Enter, Space, Escape, Pfeiltasten bedienen
- Screen-Reader: VoiceOver (macOS) oder NVDA (Windows)
- Zoom: Seite auf 200% vergrößern — darf nicht brechen
- Farbfilter: Simulation von Farbenblindheit (Chrome DevTools)
prefers-reduced-motion
Das System respektiert die Benutzer-Einstellung für reduzierte Bewegung:
- reset.css: Setzt
animation-durationundtransition-durationglobal auf 0.01ms - scroll-reveal.ts: Zeigt alle Elemente sofort (keine Scroll-Animation)
- Gallery Lightbox: Kein Scale-Overgang bei Dialog-Open
- Navigation: Kein Slide-Übergang im Mobile-Menu
Testen: macOS → Systemeinstellungen → Bedienungshilfen → Anzeige → "Bewegung reduzieren"