diff --git a/README.md b/README.md index cab95cb..e26c7c1 100644 --- a/README.md +++ b/README.md @@ -340,4 +340,19 @@ Es werden keine IP-Adressen oder sonstigen persönlichen Daten gespeichert, ledi Dieses Projekt steht unter der [MIT-Lizenz](LICENSE). --- -(c) 2025 [Markus Busche](https://digitalcourage.social/@elpatron) \ No newline at end of file +(c) 2025 [Markus Busche](https://digitalcourage.social/@elpatron) + +## Barrierefreiheit (Accessibility) + +Elpatrons Datumsrechner ist barrierefrei gestaltet und erfüllt zentrale Anforderungen an Accessibility (a11y): + +- **Semantische HTML-Struktur:** Überschriften, Labels und Formularelemente sind korrekt ausgezeichnet und verknüpft. +- **ARIA-Attribute:** Accordion und Statusmeldungen sind mit ARIA-Attributen versehen, damit Screenreader die Struktur und Zustände erkennen. +- **Tastaturbedienbarkeit:** Alle interaktiven Elemente (Accordion, Buttons, Formulare) sind vollständig per Tastatur bedienbar (inkl. Fokus-Indikator und Pfeiltasten-Navigation im Accordion). +- **Fokus-Indikatoren:** Deutliche visuelle Hervorhebung des Fokus für alle Bedienelemente. +- **Farbkontraste:** Hohe Kontraste für Texte, Buttons und Ergebnisboxen, geprüft nach WCAG-Richtlinien. +- **Status- und Fehlermeldungen:** Ergebnisse und Fehler werden mit `aria-live` für Screenreader zugänglich gemacht. +- **Mobile Optimierung:** Zusätzliche Meta-Tags für bessere Bedienbarkeit auf mobilen Geräten und Unterstützung von Screenreadern. +- **SEO:** Das Thema Barrierefreiheit ist in den Meta-Tags für Suchmaschinen sichtbar. + +Damit ist die App für Menschen mit unterschiedlichen Einschränkungen (z.B. Sehbehinderung, motorische Einschränkungen) gut nutzbar und entspricht modernen Webstandards. \ No newline at end of file diff --git a/static/style.css b/static/style.css index 4cd668a..723334b 100644 --- a/static/style.css +++ b/static/style.css @@ -82,9 +82,7 @@ input[type="date"] { .today-btn:hover { background: var(--primary); } -button { - margin-top: 0.7em; - padding: 0.55em 1.3em; +button, .accordion-header { background: var(--primary); color: #fff; border: none; @@ -95,9 +93,15 @@ button { box-shadow: 0 1px 3px rgba(30,41,59,0.05); transition: background 0.2s; } -button:hover { +button:hover, .accordion-header:hover { background: var(--primary-dark); } +button:focus, .accordion-header:focus { + outline: 3px solid #facc15; + outline-offset: 2px; + box-shadow: 0 0 0 4px #1e293b; + z-index: 2; +} .result { margin-top: 1em; font-weight: bold; @@ -106,6 +110,7 @@ button:hover { border-radius: 6px; padding: 0.7em 1em; box-shadow: 0 1px 2px rgba(30,41,59,0.04); + border: 2px solid #2563eb; } .accordion { border-radius: 12px; diff --git a/templates/index.html b/templates/index.html index 4ee5f3a..6d5a157 100644 --- a/templates/index.html +++ b/templates/index.html @@ -10,14 +10,21 @@ Elpatrons Datumsrechner – Open Source Kalender- und Datumsberechnungen - - + + + + + + + + + @@ -28,15 +35,37 @@ document.getElementById(id).value = today; } function openAccordion(idx) { - document.querySelectorAll('.accordion-header').forEach((btn, i) => { + const headers = document.querySelectorAll('.accordion-header'); + const panels = document.querySelectorAll('.accordion-content'); + headers.forEach((btn, i) => { btn.classList.toggle('active', i === idx); + btn.setAttribute('aria-expanded', i === idx ? 'true' : 'false'); }); - document.querySelectorAll('.accordion-content').forEach((el, i) => { + panels.forEach((el, i) => { el.classList.toggle('active', i === idx); }); } document.addEventListener('DOMContentLoaded', function() { openAccordion(parseInt("{{ active_idx|default(0) }}")); + // Tastatursteuerung für Accordion + const headers = document.querySelectorAll('.accordion-header'); + headers.forEach((header, idx) => { + header.addEventListener('keydown', function(e) { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + openAccordion(idx); + headers[idx].focus(); + } else if (e.key === 'ArrowDown') { + e.preventDefault(); + const next = (idx + 1) % headers.length; + headers[next].focus(); + } else if (e.key === 'ArrowUp') { + e.preventDefault(); + const prev = (idx - 1 + headers.length) % headers.length; + headers[prev].focus(); + } + }); + }); }); if ('serviceWorker' in navigator) { window.addEventListener('load', function() { @@ -53,35 +82,36 @@
- -
+
-