BFSG 2025: Was das Barrierefreiheitsstärkungsgesetz für Websites bedeutet
Das BFSG verpflichtet Unternehmen zur digitalen Barrierefreiheit. So funktionieren die Anforderungen, Fristen, WCAG-Kriterien und konkrete Umsetzungsschritte.
Rechtliches & Info
Schritt-für-Schritt-Anleitung zur technischen BFSG-Umsetzung in Astro-Projekten: Semantische HTML-Struktur, ARIA-Rollen, Fokus-Management und reduced-motion.
Das Barrierefreiheitsstärkungsgesetz (BFSG) verpflichtet private Unternehmen ab dem 28. Juni 2025 zur technischen Barrierefreiheit ihrer digitalen Produkte. Die rechtliche Grundlage ist die europäische Accessibility-Richtlinie EN 301 549 — operationalisiert über WCAG 2.1 Level AA. Dieser Artikel zeigt, wie man diese Anforderungen in Astro-Projekten technisch umsetzt, nicht nur formal erfüllt.
Barrierefreiheit beginnt nicht mit ARIA — sie beginnt mit semantischem HTML. Screenreader, Braille-Ausgaben und assistive Technologien nutzen die native Semantik des HTMLs, bevor sie ARIA-Attribute verarbeiten.
---
// layouts/Layout.astro
---
<html lang="de">
<head><!-- ... --></head>
<body>
<a href="#main-content" class="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:z-50 focus:px-4 focus:py-2 focus:bg-primary-600 focus:text-white focus:rounded-lg">
Zum Hauptinhalt springen
</a>
<header role="banner">
<nav aria-label="Hauptnavigation"><!-- ... --></nav>
</header>
<main id="main-content" tabindex="-1">
<slot />
</main>
<footer role="contentinfo"><!-- ... --></footer>
</body>
</html>
Der Skip-Link ist Pflicht nach WCAG 2.4.1. Das tabindex="-1" auf <main> ermöglicht programmatisches Fokussieren nach der Navigation — ohne es im Tab-Reihenfolge zu erscheinen.
Jede Seite darf genau eine <h1> haben. Die Hierarchie muss logisch sein — <h3> darf nicht direkt auf <h1> folgen, wenn <h2> fehlt.
---
// Eine typisch fehlerhafte Pattern:
// <h1>Seitentitel</h1>
// <h3>Abschnitt</h3> ← FEHLER: h2 fehlt
// Korrekt:
// <h1>Seitentitel</h1>
// <h2>Hauptabschnitt</h2>
// <h3>Unterabschnitt</h3>
---
ARIA (Accessible Rich Internet Applications) ergänzt semantisches HTML — es ersetzt es nicht. Die erste Regel der ARIA-Nutzung lautet: “Wenn Sie ein natives HTML-Element oder -Attribut mit der benötigten Semantik und dem gewünschten Verhalten verwenden können, tun Sie das, anstatt ein Element umzunutzen und eine ARIA-Rolle hinzuzufügen.”
---
interface Props {
isOpen: boolean;
onClose: () => void;
}
---
<!-- Dialog/Modal — natives <dialog> bevorzugen -->
<dialog
aria-labelledby="dialog-title"
aria-describedby="dialog-desc"
aria-modal="true"
>
<h2 id="dialog-title">Bestätigung erforderlich</h2>
<p id="dialog-desc">Möchten Sie diese Aktion wirklich ausführen?</p>
<button type="button" autofocus>Bestätigen</button>
<button type="button">Abbrechen</button>
</dialog>
<!-- Tabs — aria-selected + role="tabpanel" -->
<div role="tablist" aria-label="Produktkategorien">
<button
role="tab"
aria-selected="true"
aria-controls="panel-seo"
id="tab-seo"
>SEO</button>
<button
role="tab"
aria-selected="false"
aria-controls="panel-webdesign"
id="tab-webdesign"
tabindex="-1"
>Webdesign</button>
</div>
<div role="tabpanel" id="panel-seo" aria-labelledby="tab-seo">
<!-- Inhalt SEO -->
</div>
Wenn Inhalte sich dynamisch ändern — Suchergebnisse, Formularbeststätigungen, Statusmeldungen — muss das Screenreader mitbekommen:
<!-- Statusmeldungen -->
<div
role="status"
aria-live="polite"
aria-atomic="true"
class="sr-only"
id="form-status"
>
<!-- Wird via JS befüllt: "Formular erfolgreich abgesendet" -->
</div>
<!-- Fehlermeldungen mit höherer Priorität -->
<div
role="alert"
aria-live="assertive"
class="sr-only"
id="form-error"
>
</div>
Alle interaktiven Elemente müssen per Tastatur erreichbar und bedienbar sein. Das betrifft nicht nur offensichtliche Elemente wie Buttons und Links, sondern auch Custom-Komponenten.
// components/molecules/Dropdown.jsx
import { useState, useRef, useEffect } from 'react';
export function Dropdown({ label, items }) {
const [open, setOpen] = useState(false);
const triggerRef = useRef(null);
const menuRef = useRef(null);
useEffect(() => {
if (open && menuRef.current) {
// Fokus auf erstes Menü-Item beim Öffnen
const firstItem = menuRef.current.querySelector('[role="menuitem"]');
firstItem?.focus();
}
}, [open]);
function handleKeyDown(e) {
if (e.key === 'Escape') {
setOpen(false);
// Fokus zurück auf Trigger
triggerRef.current?.focus();
}
if (e.key === 'ArrowDown') {
e.preventDefault();
const items = menuRef.current?.querySelectorAll('[role="menuitem"]');
const current = document.activeElement;
const idx = Array.from(items ?? []).indexOf(current);
items?.[idx + 1]?.focus();
}
if (e.key === 'ArrowUp') {
e.preventDefault();
const items = menuRef.current?.querySelectorAll('[role="menuitem"]');
const current = document.activeElement;
const idx = Array.from(items ?? []).indexOf(current);
items?.[idx - 1]?.focus();
}
}
return (
<div onKeyDown={handleKeyDown}>
<button
ref={triggerRef}
aria-haspopup="menu"
aria-expanded={open}
onClick={() => setOpen(!open)}
>
{label}
</button>
{open && (
<ul role="menu" ref={menuRef}>
{items.map((item) => (
<li key={item.href} role="none">
<a role="menuitem" href={item.href}>{item.label}</a>
</li>
))}
</ul>
)}
</div>
);
}
WCAG 2.4.11 (Level AA ab WCAG 2.2) fordert sichtbare Fokus-Indikatoren. Die outline: none-Praxis aus den 2010er-Jahren ist nach BFSG nicht akzeptabel:
/* In global.css — niemals :focus-visible unterdrücken */
:focus-visible {
outline: 2px solid var(--color-primary-500);
outline-offset: 2px;
border-radius: 4px;
}
/* Eigene Fokus-Stile für spezifische Elemente */
.btn:focus-visible {
outline: 2px solid var(--color-primary-500);
outline-offset: 3px;
box-shadow: 0 0 0 4px var(--color-primary-100);
}
WCAG 1.4.3 fordert ein Kontrastverhältnis von mindestens 4,5:1 für normalen Text und 3:1 für großen Text (18pt / 14pt bold). Für nicht-textliche Elemente (Buttons, Icons, Formularrahmen) gilt 3:1.
/* Primärfarbe prüfen — bei Wender Media Blau auf weiß: */
/* #0072BB auf #FFFFFF → Kontrastverhältnis: 5.74:1 ✓ */
/* #0072BB auf #f3f4f6 → Kontrastverhältnis: 5.33:1 ✓ */
/* Problematisch: hellgraues Placeholder-Text */
/* color: #9ca3af auf #FFFFFF → 2.32:1 ✗ */
/* Lösung: mindestens #6b7280 verwenden → 4.48:1 ✓ */
Für interaktive Elemente im Hover-Zustand muss der Kontrast ebenfalls eingehalten werden — nicht nur im Ausgangszustand.
Nutzer, die in ihrem Betriebssystem “Bewegung reduzieren” aktiviert haben, leiden oft unter vestibulären Störungen, bei denen Animationen Schwindel oder Übelkeit auslösen können. CSS und JavaScript müssen diesen Wunsch respektieren.
/* Globale Regel in global.css */
@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;
}
}
In React-/Preact-Inseln:
import { useEffect, useState } from 'react';
function useReducedMotion() {
const [reduced, setReduced] = useState(false);
useEffect(() => {
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
setReduced(mq.matches);
const handler = (e) => setReduced(e.matches);
mq.addEventListener('change', handler);
return () => mq.removeEventListener('change', handler);
}, []);
return reduced;
}
export function AnimatedHero() {
const reduced = useReducedMotion();
return (
<div
style={{
transition: reduced ? 'none' : 'transform 0.4s ease',
}}
>
{/* ... */}
</div>
);
}
Formulare sind der häufigste Fehlerbereich bei BFSG-Audits. Die wichtigsten Anforderungen:
<form novalidate>
<!-- Pflichtfeld: label ist mit input assoziiert -->
<div class="field-group">
<label for="email" class="block text-sm font-medium text-gray-700">
E-Mail-Adresse
<span aria-hidden="true" class="text-red-500 ml-1">*</span>
</label>
<input
type="email"
id="email"
name="email"
required
aria-required="true"
aria-describedby="email-hint email-error"
autocomplete="email"
class="mt-1 block w-full rounded-lg border border-gray-300 px-3 py-2"
/>
<p id="email-hint" class="mt-1 text-sm text-gray-500">
Format: name@beispiel.de
</p>
<!-- Fehlermeldung — nur sichtbar wenn ungültig -->
<p id="email-error" role="alert" class="mt-1 text-sm text-red-600 hidden">
Bitte geben Sie eine gültige E-Mail-Adresse ein.
</p>
</div>
<!-- Submit-Button: immer type="submit" -->
<button type="submit" class="btn-primary">
Anfrage senden
</button>
</form>
<!-- Informatives Bild: alt beschreibt Inhalt und Funktion -->
<img
src="/images/bfsg-checkliste.webp"
alt="BFSG-Checkliste mit 12 Prüfpunkten für barrierefreie Websites"
width="800"
height="450"
/>
<!-- Dekoratives Bild: alt="" verhindert, dass Screenreader die URL vorliest -->
<img src="/images/decoration-wave.svg" alt="" aria-hidden="true" />
<!-- Icon mit Bedeutung: aria-label am übergeordneten Element -->
<button type="button" aria-label="Suche öffnen">
<svg aria-hidden="true" focusable="false"><!-- ... --></svg>
</button>
Automatisierte Tools erkennen ca. 30–40% aller WCAG-Verstöße. Der Rest erfordert manuelle Prüfung:
BFSG-Audit für Ihr Projekt? Wender Media führt technische Accessibility-Audits durch und behebt Barrieren systematisch — info@wendermedia.info.
Themen:
Wender Media unterstützt Sie bei der praktischen Umsetzung — von der technischen Konzeption bis zum Launch. Schreiben Sie uns, wir antworten innerhalb von 24 Stunden.
Jetzt Beratung anfragenKostenlos & unverbindlich — info@wendermedia.info
Das BFSG verpflichtet Unternehmen zur digitalen Barrierefreiheit. So funktionieren die Anforderungen, Fristen, WCAG-Kriterien und konkrete Umsetzungsschritte.
Wie ARIA Landmarks Screenreader-Nutzern helfen, eine Website zu navigieren. Praktische Anleitung für banner, main, navigation und weitere Rollen.
So funktioniert ein systematischer Accessibility Audit: WCAG-Checkliste, Testing-Tools, Screenreader-Tests und Priorisierung von Barrierefreiheits-Maßnahmen.