Barrierefreiheit-Widget: Storefront-Integration
Barrierefreiheit-Widget für Sylius - Twig Hooks, Skip-Link-Ziel, Theming per CSS Custom Properties, Theme-Kompatibilität
Barrierefreiheit-Widget: Storefront-Integration
Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Twig Hooks
Das Plugin registriert sich über folgende Hooks, kein Core-Template wird überschrieben:
| Hook | Zweck |
|---|---|
sylius_shop.base#stylesheets |
Lädt accessibility.css; bei mindestens einem aktiven Werkzeug außerdem accessibility-early.js (synchron, vor dem ersten Rendern) und, bei aktivem Farbfilter, einen Inline-<style> mit den Filterregeln |
sylius_shop.base#javascripts |
Lädt accessibility.js (defer), nur wenn mindestens ein Werkzeug aktiv ist |
sylius_shop.base.header |
Skip-Link (Priorität 1000, ganz vorn) und das Sprungziel (Priorität 50) |
sylius_shop.base.offcanvas |
Das schwebende Widget selbst (Priorität -100), außerhalb des Seiten-Wrappers |
Ein Theme, das diese Hook-Slots ersetzt, muss die Templates des Plugins selbst rendern, sonst erscheint nichts.
Skip-Link und Sprungziel
Der Skip-Link ist ein Link <a class="mmd-a11y-skip-link" href="#mmd-a11y-main"> mit dem Text „Zum Hauptinhalt springen“ (EN: „Skip to main content“). Er ist per CSS außerhalb des Bildschirms und erscheint nur, wenn er den Tastaturfokus bekommt.
Die Basis-Vorlage des Shops hat kein <main> und keine Inhalts-ID. Das Plugin gibt deshalb selbst einen leeren, fokussierbaren <div id="mmd-a11y-main" tabindex="-1" role="region"> mit aria-label („Hauptinhalt“) aus, und zwar im Hook sylius_shop.base.header zwischen der Navigation (Priorität 100) und den Flash-Nachrichten (Priorität 0), damit eine Validierungsmeldung oder „In den Warenkorb gelegt“-Nachricht nach dem Sprung nicht übersprungen wird. Link und Ziel erscheinen nur, wenn die Einstellung für den Skip-Link im Channel eingeschaltet ist.
Setzt dein Theme den Inhalt an anderer Stelle, überschreibe das Template des Plugins nach dem üblichen Symfony-Muster unter templates/bundles/MmdSyliusAccessibilityPlugin/shop/skip_target.html.twig (Original: templates/shop/skip_target.html.twig im Plugin).
Theming
Die Effekte sind einfache Klassen auf <html>, Farben/Abstände über CSS Custom Properties aus deinem Theme überschreibbar:
:root {
--mmd-a11y-primary: #0b6b3a;
--mmd-a11y-primary-dark: #08522c;
--mmd-a11y-offset-x: 24px;
--mmd-a11y-offset-bottom: 90px;
--mmd-a11y-z-index: 1020;
}
Weitere Properties im Stylesheet: --mmd-a11y-bg, --mmd-a11y-text, --mmd-a11y-text-light, --mmd-a11y-border, --mmd-a11y-control-border, --mmd-a11y-focus, --mmd-a11y-hover, --mmd-a11y-size und --mmd-a11y-panel-width.
| Einstellung | Klassen auf <html> |
|---|---|
| Schriftgröße | mmd-a11y-font-small, mmd-a11y-font-large |
| Kontrast | mmd-a11y-contrast-high, mmd-a11y-contrast-inverted |
| Farbfilter | mmd-a11y-filter-protanopia, -deuteranopia, -tritanopia |
| Blaulicht | mmd-a11y-blue-light |
| Animationen reduzieren | mmd-a11y-reduce-motion |
localStorage-Key: mmd-accessibility-settings. Eine Headless-Storefront kann dieselben Klassen als Konvention wiederverwenden (siehe Shop API).
Die Farbfilter sitzen bewusst auf
<html>, nicht auf einem Wrapper-Element: Ein Filter auf einem Wrapper würde zum Containing Block jedesposition: fixed-Elements (Sticky-Header, Banner) und dessen Platzierung zerstören.
Verhalten im Detail
- Kein Aufblitzen beim Laden. Ein kleines synchrones Script im
<head>(accessibility-early.js, eine externe Datei, damit eine strikte CSP keine Ausnahme dafür braucht) setzt die gespeicherten Einstellungen vor dem ersten Rendern auf<html>. Das Widget-Script baut darauf auf. - Die Schriftgröße ist relativ. „Klein“ und „Groß“ setzen die Schrift auf
<html>auf 87,5 % und 125 % der Browser-Einstellung des Besuchers, sie ersetzen sie nie durch eine feste Pixelgröße. - Kontrast. „Hoch“ legt
filter: contrast(1.35)auf<html>, „Invertiert“invert(1) hue-rotate(180deg). Bilder und Videos bekommen einen Gegenfilter, damit Fotos ihr natürliches Aussehen behalten. - Blaulichtfilter. Eine halbtransparente, gelb-orange Fläche (12 % Deckkraft) liegt über der Seite und fängt keine Klicks ab.
- Animationen reduzieren. Animations- und Übergangsdauern werden praktisch auf null gesetzt, sanftes Scrollen wird abgeschaltet. Ist im Betriebssystem bereits „Bewegung reduzieren“ gesetzt, gilt dieselbe Regel auch ohne Widget-Auswahl.
- Das Panel ist ein nicht-modaler Dialog. Die Seite dahinter bleibt bedienbar, deshalb gibt es keinen Fokus-Trap. Es schließt per Esc, per Klick daneben und wenn der Tastaturfokus es verlässt. „Alle Einstellungen zurücksetzen“ stellt alle Werkzeuge auf den Normalzustand zurück.
- Die Farbfilter sind eine Näherung. Sie bestehen aus drei fest hinterlegten 3×3-Farbmatrizen (SVG
feColorMatrix) für Protanopie, Deuteranopie und Tritanopie. Das ist kein Brettel-Algorithmus und keine Messung; wie gut ein Filter einer bestimmten Farbsehschwäche entspricht oder hilft, sichert das Plugin nicht zu. Die Filterregeln werden inline ausgegeben, weilurl('#id')in einer externen Stylesheet die Inline-SVG-Filter nicht erreicht; eine strikte Content-Security-Policy braucht dafür einen Nonce oder Hash für diesen<style>. - Asset-URLs entstehen ohne
asset(): Solange ein Sylius-Theme aktiv ist, schreibt es Bundle-Assets auf/_themes/...um, das erst nachsylius:theme:assets:installexistiert. Die Änderungszeit der Datei dient als Cache-Busting-Version. - Abgeschaltete Werkzeuge. Die gespeicherte Wahl eines Besuchers für ein Werkzeug, das der Channel nicht mehr anbietet, wird ignoriert.