⭐ Featured

Barrierefreie Website BFSG 2025: Technische Anforderungen & Code-Beispiele

Kompletter technischer Leitfaden zur BFSG-konformen Website: WCAG 2.1 Level AA Umsetzung, HTML/CSS/JavaScript Best Practices, Testing-Tools und Entwickler-Workflows für Barrierefreiheit.

Barrierefreie Website BFSG 2025: Technische Anforderungen & Code-Beispiele

Das Barrierefreiheitsstärkungsgesetz (BFSG) verpflichtet ab dem 28. Juni 2025 alle Unternehmen mit mehr als 10 Mitarbeitern oder einem Jahresumsatz über 2 Millionen Euro zur barrierefreien Gestaltung ihrer digitalen Dienste. Für Entwickler und technische Entscheider bedeutet dies: WCAG 2.1 Level AA Konformität ist Pflicht.

Dieser Guide zeigt Ihnen konkrete technische Umsetzung mit Code-Beispielen, Testing-Tools und Best Practices für BFSG-konforme Websites.

Was bedeutet BFSG technisch?

Die rechtliche Grundlage

  • Gesetz: Barrierefreiheitsstärkungsgesetz (BFSG)
  • Deadline: 28. Juni 2025
  • Standard: WCAG 2.1 Level AA (Web Content Accessibility Guidelines)
  • Strafen: Bis zu 100.000€ Bußgeld + Abmahnrisiko
  • Betroffen: Online-Shops, Websites, Web-Apps, digitale Dienstleistungen

WCAG 2.1 Level AA: Die 4 Prinzipien

Die WCAG basiert auf 4 Grundprinzipien (POUR):

  1. Perceivable (Wahrnehmbar): Inhalte müssen für alle Sinne zugänglich sein
  2. Operable (Bedienbar): Navigation ohne Maus möglich
  3. Understandable (Verständlich): Klare Sprache, konsistente Bedienung
  4. Robust (Robust): Kompatibel mit assistiven Technologien

1. Semantisches HTML: Die Basis jeder barrierefreien Website

Problem: Div-Suppe ohne Struktur

Falsch (nicht barrierefrei):

<div class="header">
  <div class="nav">
    <div class="link">Home</div>
    <div class="link">Über uns</div>
  </div>
</div>
<div class="content">
  <div class="article">
    <div class="title">Artikel-Überschrift</div>
    <div class="text">Artikeltext...</div>
  </div>
</div>

Warum ist das schlecht?

  • Screen Reader können Struktur nicht erkennen
  • Keine semantische Navigation möglich
  • Suchmaschinen verstehen Hierarchie nicht
  • Keine Landmark-Navigation

Lösung: Semantische HTML5-Elemente

Richtig (barrierefrei):

<header>
  <nav aria-label="Hauptnavigation">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/ueber-uns">Über uns</a></li>
    </ul>
  </nav>
</header>

<main>
  <article>
    <h1>Artikel-Überschrift</h1>
    <p>Artikeltext...</p>
  </article>
</main>

<footer>
  <p>&copy; 2025 Wendermedia</p>
</footer>

Vorteile:

  • Screen Reader erkennen Landmarks (<main>, <nav>, <header>, <footer>)
  • Nutzer können direkt zum Hauptinhalt springen
  • Bessere SEO durch klare Struktur
  • Konsistente User Experience

Überschriften-Hierarchie

Falsch:

<h1>Hauptüberschrift</h1>
<h3>Unterüberschrift</h3> <!-- h2 übersprungen! -->
<h2>Weitere Überschrift</h2> <!-- Falsche Reihenfolge -->

Richtig:

<h1>Hauptüberschrift</h1>
<h2>Unterüberschrift Ebene 2</h2>
  <h3>Unterüberschrift Ebene 3</h3>
  <h3>Weitere Ebene 3</h3>
<h2>Weitere Ebene 2</h2>

WCAG-Kriterium: 1.3.1 Info and Relationships (Level A)

Best Practice:

  • Genau eine <h1> pro Seite (Seitentitel)
  • Logische Hierarchie ohne Sprünge (h1 → h2 → h3, nicht h1 → h3)
  • Keine Überschriften aus rein optischen Gründen

2. Tastaturnavigation: Alles muss bedienbar sein

Fokus-Management

Falsch (Maus-only):

<div onclick="openModal()">Öffnen</div>

Problem: Funktioniert nur mit Maus, nicht mit Tastatur oder Screen Reader.

Richtig (tastaturzugänglich):

<button type="button" onclick="openModal()">Öffnen</button>

Noch besser mit Event-Listener:

<button type="button" id="open-modal">Öffnen</button>

<script>
document.getElementById('open-modal').addEventListener('click', function() {
  openModal();
});

// Zusätzlich: Escape-Taste zum Schließen
document.addEventListener('keydown', function(e) {
  if (e.key === 'Escape' && modalIsOpen) {
    closeModal();
  }
});
</script>

Fokus-Sichtbarkeit

Falsch (Fokus unsichtbar):

/* NIEMALS machen! */
*:focus {
  outline: none;
}

Richtig (deutlicher Fokus-Indikator):

a:focus, button:focus, input:focus {
  outline: 3px solid #0066cc;
  outline-offset: 2px;
}

/* Modernes Focus-visible (nur Tastatur) */
a:focus-visible, button:focus-visible, input:focus-visible {
  outline: 3px solid #0066cc;
  outline-offset: 2px;
  box-shadow: 0 0 0 4px rgba(0, 102, 204, 0.2);
}

WCAG-Kriterium: 2.4.7 Focus Visible (Level AA)

Kontrastverhältnis für Fokus-Indikatoren: Mindestens 3:1 zum Hintergrund

Tastatur-Shortcuts

Standard-Tastaturnavigation (muss funktionieren):

  • Tab: Nächstes fokussierbares Element
  • Shift + Tab: Vorheriges Element
  • Enter: Links/Buttons aktivieren
  • Leertaste: Buttons/Checkboxen aktivieren
  • Pfeiltasten: Dropdown-Menüs, Radio-Buttons
  • Escape: Modals/Dialoge schließen

Best Practice für Skip-Links:

<a href="#main-content" class="skip-link">Zum Hauptinhalt springen</a>

<header>...</header>

<main id="main-content">
  <!-- Hauptinhalt -->
</main>

<style>
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  background: #000;
  color: #fff;
  padding: 8px;
  z-index: 9999;
}

.skip-link:focus {
  top: 0;
}
</style>

3. Barrierefreie Formulare

Label und Input-Verknüpfung

Falsch:

<div>Name:</div>
<input type="text" placeholder="Ihr Name">

Probleme:

  • Screen Reader lesen keine Labels vor
  • Placeholder verschwindet bei Eingabe
  • Kein Klick auf Label möglich

Richtig:

<label for="name">Name *</label>
<input type="text" id="name" name="name" required
       aria-required="true" aria-describedby="name-hint">
<span id="name-hint" class="hint">Bitte Vor- und Nachname eingeben</span>

Fehlermeldungen

Falsch (nur rot färben):

<input type="email" style="border-color: red;">

Richtig (mit ARIA):

<label for="email">E-Mail-Adresse *</label>
<input type="email" id="email" name="email"
       aria-invalid="true"
       aria-describedby="email-error">
<span id="email-error" role="alert" class="error">
  ⚠️ Bitte geben Sie eine gültige E-Mail-Adresse ein
</span>

WCAG-Kriterium: 3.3.1 Error Identification (Level A)

Komplexes Formular-Beispiel

<form method="post" aria-labelledby="form-title">
  <h2 id="form-title">Kontaktformular</h2>

  <!-- Feldgruppe -->
  <fieldset>
    <legend>Persönliche Daten</legend>

    <div class="form-group">
      <label for="firstname">Vorname *</label>
      <input type="text" id="firstname" name="firstname"
             required aria-required="true" autocomplete="given-name">
    </div>

    <div class="form-group">
      <label for="lastname">Nachname *</label>
      <input type="text" id="lastname" name="lastname"
             required aria-required="true" autocomplete="family-name">
    </div>
  </fieldset>

  <!-- Radio-Buttons -->
  <fieldset>
    <legend>Anrede</legend>
    <div>
      <input type="radio" id="herr" name="anrede" value="herr">
      <label for="herr">Herr</label>
    </div>
    <div>
      <input type="radio" id="frau" name="anrede" value="frau">
      <label for="frau">Frau</label>
    </div>
    <div>
      <input type="radio" id="divers" name="anrede" value="divers">
      <label for="divers">Divers</label>
    </div>
  </fieldset>

  <!-- Submit Button -->
  <button type="submit">Absenden</button>
</form>

Best Practices:

  • <fieldset> + <legend> für zusammengehörige Felder
  • autocomplete-Attribute für Autofill
  • Pflichtfelder mit * und required
  • Fehlermeldungen mit role="alert"

4. Farbkontrast & visuelle Gestaltung

Kontrastverhältnisse nach WCAG 2.1

WCAG Level AA Anforderungen:

  • Normal Text (unter 18pt): Mindestens 4.5:1
  • Großer Text (ab 18pt oder 14pt fett): Mindestens 3:1
  • UI-Komponenten (Buttons, Icons): Mindestens 3:1

Falsch (zu geringer Kontrast):

/* Kontrast nur 2.8:1 - nicht ausreichend! */
.text {
  color: #999999;
  background: #ffffff;
}

Richtig (ausreichender Kontrast):

/* Kontrast 7.0:1 - WCAG AAA konform */
.text {
  color: #333333;
  background: #ffffff;
}

/* Oder: */
.text-inverted {
  color: #ffffff;
  background: #0066cc; /* Kontrast 4.6:1 */
}

Farbe allein reicht nicht

Falsch (nur Farbe für Information):

<p style="color: red;">Fehler aufgetreten</p>
<p style="color: green;">Erfolgreich gespeichert</p>

Richtig (Farbe + Icon + Text):

<p class="error">
  <span aria-hidden="true">⚠️</span>
  <span class="sr-only">Fehler:</span>
  Fehler aufgetreten
</p>

<p class="success">
  <span aria-hidden="true">✅</span>
  <span class="sr-only">Erfolg:</span>
  Erfolgreich gespeichert
</p>

WCAG-Kriterium: 1.4.1 Use of Color (Level A)

Testing-Tools für Kontrast

Online-Tools:

Browser-Extensions:

  • WAVE (Chrome, Firefox)
  • axe DevTools (Chrome, Firefox)

Command-Line:

# Pa11y für automatisierte Tests
npm install -g pa11y
pa11y https://ihre-website.de --standard WCAG2AA

5. Alternative Texte für Bilder

Bilder richtig beschreiben

Falsch:

<img src="team.jpg">
<img src="logo.png" alt="Bild">
<img src="chart.png" alt="chart.png">

Richtig:

<!-- Informatives Bild -->
<img src="team.jpg" alt="Unser Team von 5 Mitarbeitern im Büro bei der Arbeit">

<!-- Dekoratives Bild (kein alt-Text nötig) -->
<img src="decoration.svg" alt="" role="presentation">

<!-- Logo -->
<img src="logo.png" alt="Wendermedia - Webdesign aus Halle">

<!-- Komplexes Diagramm mit Langbeschreibung -->
<img src="sales-chart.png" alt="Umsatzentwicklung 2024"
     aria-describedby="chart-description">
<div id="chart-description">
  <p>Detaillierte Beschreibung: Der Umsatz stieg von 100.000€ im Januar
     auf 250.000€ im Dezember 2024. Besonders stark war das Wachstum
     im 3. Quartal mit +80%.</p>
</div>

Best Practices:

  • Informative Bilder: Kurze Beschreibung des Inhalts/der Funktion
  • Dekorative Bilder: Leeres alt="" (nicht weglassen!)
  • Komplexe Grafiken: alt + längere Beschreibung via aria-describedby
  • Icon-Buttons: aria-label statt alt

SVG-Icons barrierefrei

Falsch:

<svg class="icon">...</svg>

Richtig:

<!-- Dekoratives Icon -->
<svg class="icon" aria-hidden="true" focusable="false">...</svg>

<!-- Informatives Icon mit Label -->
<button aria-label="Suchen">
  <svg aria-hidden="true" focusable="false">
    <!-- Icon-Pfade -->
  </svg>
</button>

<!-- SVG mit Titel und Beschreibung -->
<svg role="img" aria-labelledby="icon-title icon-desc">
  <title id="icon-title">Erfolgreich</title>
  <desc id="icon-desc">Grüner Haken für erfolgreiche Aktion</desc>
  <!-- Icon-Pfade -->
</svg>

6. Video & Audio barrierefrei

Video mit Untertiteln und Audiodeskription

<video controls>
  <source src="video.mp4" type="video/mp4">

  <!-- Untertitel (Deutsch) -->
  <track kind="subtitles" src="video-de.vtt" srclang="de" label="Deutsch" default>

  <!-- Untertitel (Englisch) -->
  <track kind="subtitles" src="video-en.vtt" srclang="en" label="English">

  <!-- Audiodeskription -->
  <track kind="descriptions" src="video-ad.vtt" srclang="de" label="Audiodeskription">

  <!-- Fallback -->
  <p>Ihr Browser unterstützt kein HTML5 Video.
     <a href="video.mp4">Video herunterladen</a>
  </p>
</video>

<!-- Transkript -->
<details>
  <summary>Vollständiges Transkript anzeigen</summary>
  <div>
    <h3>Transkript: Produktvorstellung</h3>
    <p><strong>0:00</strong> - Willkommen zu unserer Produktvorstellung...</p>
    <p><strong>0:15</strong> - Das neue Feature ermöglicht...</p>
  </div>
</details>

WCAG-Anforderungen:

  • Level A: Untertitel für aufgezeichnete Videos
  • Level AA: Audiodeskription oder Volltext-Alternative
  • Level AAA: Gebärdensprache-Übersetzung

WebVTT-Datei Beispiel (video-de.vtt)

WEBVTT

00:00:00.000 --> 00:00:03.000
Willkommen zu unserer Produktvorstellung.

00:00:03.500 --> 00:00:07.000
Heute zeigen wir Ihnen unser neues Feature.

00:00:07.500 --> 00:00:11.000
Es ermöglicht Ihnen, Ihre Workflows zu optimieren.

7. ARIA (Accessible Rich Internet Applications)

ARIA-Grundregeln

Die 5 goldenen ARIA-Regeln:

  1. No ARIA is better than bad ARIA - Nutze natives HTML
  2. Don’t change native semantics - <button role="link"> ist falsch
  3. All interactive ARIA controls must be keyboard accessible
  4. Don’t use role="presentation" or aria-hidden="true" on focusable elements
  5. All interactive elements must have an accessible name

ARIA Roles

<!-- Navigation -->
<nav role="navigation" aria-label="Hauptnavigation">...</nav>

<!-- Banner (Header) -->
<header role="banner">...</header>

<!-- Hauptinhalt -->
<main role="main">...</main>

<!-- Sidebar -->
<aside role="complementary" aria-label="Zusätzliche Informationen">...</aside>

<!-- Suche -->
<div role="search">
  <label for="search-input">Suche</label>
  <input type="search" id="search-input">
</div>

<!-- Artikelliste -->
<section role="region" aria-labelledby="blog-title">
  <h2 id="blog-title">Aktuelle Blog-Artikel</h2>
  <article>...</article>
</section>

ARIA States & Properties

aria-expanded (für Accordions/Dropdowns):

<button aria-expanded="false" aria-controls="menu">
  Menü
</button>
<ul id="menu" hidden>
  <li>Item 1</li>
  <li>Item 2</li>
</ul>

<script>
button.addEventListener('click', function() {
  const expanded = this.getAttribute('aria-expanded') === 'true';
  this.setAttribute('aria-expanded', !expanded);
  menu.hidden = expanded;
});
</script>

aria-live (für dynamische Inhalte):

<!-- Statusmeldungen -->
<div role="status" aria-live="polite" aria-atomic="true">
  <!-- Wird vom Screen Reader vorgelesen, wenn sich Inhalt ändert -->
  <p id="status-message"></p>
</div>

<!-- Fehlermeldungen (sofort vorlesen) -->
<div role="alert" aria-live="assertive">
  <!-- Unterbricht Screen Reader sofort -->
  <p id="error-message"></p>
</div>

<script>
// Status update
document.getElementById('status-message').textContent = 'Daten wurden gespeichert';

// Error
document.getElementById('error-message').textContent = 'Fehler beim Speichern!';
</script>

aria-current (für Navigation):

<nav>
  <a href="/" aria-current="page">Home</a>
  <a href="/blog">Blog</a>
  <a href="/kontakt">Kontakt</a>
</nav>
<button id="open-dialog">Dialog öffnen</button>

<div role="dialog" aria-labelledby="dialog-title" aria-modal="true"
     class="dialog" hidden>
  <div class="dialog-content">
    <h2 id="dialog-title">Bestätigung erforderlich</h2>
    <p>Möchten Sie die Änderungen wirklich verwerfen?</p>

    <div class="dialog-actions">
      <button id="confirm">Verwerfen</button>
      <button id="cancel">Abbrechen</button>
    </div>

    <button id="close-dialog" aria-label="Dialog schließen">×</button>
  </div>
</div>

<script>
const dialog = document.querySelector('[role="dialog"]');
const openBtn = document.getElementById('open-dialog');
const closeBtn = document.getElementById('close-dialog');
const cancelBtn = document.getElementById('cancel');

// Dialog öffnen
openBtn.addEventListener('click', () => {
  dialog.hidden = false;
  closeBtn.focus(); // Fokus in Dialog

  // Fokus-Falle (Trap focus im Dialog)
  document.addEventListener('keydown', trapFocus);
});

// Dialog schließen
function closeDialog() {
  dialog.hidden = true;
  openBtn.focus(); // Fokus zurück zum Trigger
  document.removeEventListener('keydown', trapFocus);
}

closeBtn.addEventListener('click', closeDialog);
cancelBtn.addEventListener('click', closeDialog);

// Escape-Taste
document.addEventListener('keydown', (e) => {
  if (e.key === 'Escape' && !dialog.hidden) {
    closeDialog();
  }
});

// Fokus-Falle im Dialog
function trapFocus(e) {
  if (e.key !== 'Tab') return;

  const focusableElements = dialog.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstElement = focusableElements[0];
  const lastElement = focusableElements[focusableElements.length - 1];

  if (e.shiftKey && document.activeElement === firstElement) {
    lastElement.focus();
    e.preventDefault();
  } else if (!e.shiftKey && document.activeElement === lastElement) {
    firstElement.focus();
    e.preventDefault();
  }
}
</script>

8. Responsive & Zoom-fähig

Responsives Design (WCAG 2.1)

WCAG-Kriterium: 1.4.10 Reflow (Level AA)

Inhalte müssen bei 320px Breite und 256px Höhe (entspricht 400% Zoom) ohne horizontales Scrollen lesbar sein.

Falsch (fixed width):

.container {
  width: 1200px; /* Bricht bei kleinen Viewports */
}

Richtig (fluid width):

.container {
  max-width: 1200px;
  width: 100%;
  padding: 0 20px;
  margin: 0 auto;
}

/* Mobile First */
@media (min-width: 768px) {
  .container {
    padding: 0 40px;
  }
}

Text-Skalierung

WCAG-Kriterium: 1.4.4 Resize Text (Level AA)

Text muss bis 200% vergrößerbar sein ohne Funktionsverlust.

Falsch (px-basiert, nicht skalierbar):

body {
  font-size: 16px; /* Skaliert nicht mit Browser-Einstellungen */
}

Richtig (rem-basiert):

/* Root Font Size (1rem = 16px bei Standard-Einstellung) */
html {
  font-size: 100%; /* Respektiert User-Einstellungen */
}

body {
  font-size: 1rem; /* 16px */
  line-height: 1.5; /* Mindestens 1.5 für Lesbarkeit */
}

h1 {
  font-size: 2.5rem; /* 40px */
  line-height: 1.2;
}

p {
  font-size: 1rem;
  margin-bottom: 1.5rem;
}

/* Minimum Font Size */
small {
  font-size: 0.875rem; /* Nicht kleiner als 14px */
}

Zeilenabstand & Zeichenabstand (WCAG 1.4.12):

p {
  line-height: 1.5; /* Mindestens 1.5x Schriftgröße */
  letter-spacing: 0.12em; /* Optional für bessere Lesbarkeit */
  word-spacing: 0.16em;
}

9. Testing & Qualitätssicherung

Automatisierte Tests

1. axe DevTools (Browser-Extension)

Installation: Chrome Web Store / Firefox Add-ons

# Oder: Command Line
npm install -g @axe-core/cli
axe https://ihre-website.de --tags wcag2aa

2. Lighthouse (in Chrome DevTools)

# Command Line
npm install -g lighthouse
lighthouse https://ihre-website.de --only-categories=accessibility --view

3. Pa11y (CI/CD Integration)

npm install -g pa11y
pa11y https://ihre-website.de --standard WCAG2AA --reporter json > report.json

4. Jest + jest-axe (Unit Tests)

// setup-tests.js
import { toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);

// component.test.js
import { render } from '@testing-library/react';
import { axe } from 'jest-axe';
import MyComponent from './MyComponent';

test('should have no accessibility violations', async () => {
  const { container } = render(<MyComponent />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

Manuelle Tests

Tastatur-Navigation:

  1. Tab durch alle interaktiven Elemente
  2. Prüfen: Fokus sichtbar? Logische Reihenfolge?
  3. Enter/Space auf Buttons testen
  4. Escape schließt Modals?

Screen Reader Tests:

NVDA (Windows - kostenlos):

1. NVDA starten (Strg + Alt + N)
2. Website öffnen
3. Mit Pfeil-Tasten durch Inhalte navigieren
4. H-Taste: Überschriften-Navigation
5. K-Taste: Links-Navigation
6. F-Taste: Formular-Navigation

VoiceOver (macOS - integriert):

1. VoiceOver aktivieren (Cmd + F5)
2. Rotor öffnen (Ctrl + Option + U)
3. Landmarks, Überschriften, Links testen
4. VO + Pfeiltasten: Navigation

Checkliste für manuelle Tests:

  • Alle Bilder haben alt-Text (oder alt="")
  • Überschriften in korrekter Reihenfolge (h1 → h2 → h3)
  • Fokus-Reihenfolge logisch
  • Fokus deutlich sichtbar
  • Alle Funktionen per Tastatur bedienbar
  • Formulare haben Labels
  • Fehlermeldungen verständlich
  • Farbkontrast ausreichend (4.5:1)
  • Text bis 200% vergrößerbar
  • Kein horizontales Scrollen bei 320px Breite
  • Videos haben Untertitel
  • Skip-Link vorhanden

Browser-Testing

Mindestens testen mit:

  • Chrome + Screen Reader
  • Firefox + Screen Reader
  • Safari + VoiceOver (macOS/iOS)
  • Edge + Narrator (Windows)

10. Entwickler-Workflow für BFSG-Konformität

Pre-Commit Hook für Accessibility

.git/hooks/pre-commit:

#!/bin/sh

echo "Running accessibility tests..."

# Pa11y für lokale HTML-Dateien
npm run test:a11y

if [ $? -ne 0 ]; then
  echo "❌ Accessibility tests failed. Commit aborted."
  exit 1
fi

echo "✅ Accessibility tests passed."

package.json:

{
  "scripts": {
    "test:a11y": "pa11y-ci --config .pa11yci.json",
    "test:a11y:report": "pa11y https://localhost:3000 --reporter html > a11y-report.html"
  },
  "devDependencies": {
    "pa11y": "^7.0.0",
    "pa11y-ci": "^3.0.1"
  }
}

.pa11yci.json:

{
  "defaults": {
    "standard": "WCAG2AA",
    "timeout": 10000,
    "wait": 500
  },
  "urls": [
    "http://localhost:3000/",
    "http://localhost:3000/blog",
    "http://localhost:3000/kontakt"
  ]
}

Continuous Integration (GitHub Actions)

.github/workflows/accessibility.yml:

name: Accessibility Tests

on: [push, pull_request]

jobs:
  a11y:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm ci

      - name: Build site
        run: npm run build

      - name: Start server
        run: npm run preview &

      - name: Wait for server
        run: npx wait-on http://localhost:4173

      - name: Run Pa11y
        run: npm run test:a11y

      - name: Run axe
        run: npx @axe-core/cli http://localhost:4173 --tags wcag2aa

VS Code Extensions für Accessibility

Empfohlene Extensions:

  • axe Accessibility Linter: Echtzeit-Warnungen im Code
  • webhint: HTML/CSS/Accessibility Linting
  • HTMLHint: HTML-Validierung
  • Stylelint: CSS-Linting mit a11y-Regeln

.vscode/extensions.json:

{
  "recommendations": [
    "deque-systems.vscode-axe-linter",
    "webhint.vscode-webhint",
    "htmlhint.vscode-htmlhint"
  ]
}

Budget & Zeitaufwand

Neues Projekt (von Anfang an barrierefrei)

PhaseAufwandKosten
Planung & Konzeption+10%+800€
Design (Kontraste, Fokus-Stile)+15%+1.200€
Entwicklung (semantisches HTML, ARIA)+20%+2.500€
Testing & QA+40%+2.000€
Gesamt Mehraufwand+20-25%+6.500€

Wichtig: Bei Planung von Anfang an ist der Mehraufwand minimal (20-25%). Nachträgliche Anpassungen kosten 3-5x mehr.

Bestehendes Projekt nachrüsten

KomplexitätAufwandKosten
Kleine Website (5-10 Seiten)40-60h4.000€ - 6.000€
Mittlere Website (20-50 Seiten)80-120h8.000€ - 12.000€
Große Website/Shop (100+ Seiten)200-400h20.000€ - 40.000€
Web-App (komplex)400-800h40.000€ - 80.000€

Kostentreiber:

  • Komplexe JavaScript-Interaktionen (Dropdown-Menüs, Modals, Carousels)
  • Video-Inhalte (Untertitel, Transkripte erstellen)
  • Dynamische Formulare mit Custom-Komponenten
  • Legacy-Code ohne semantisches HTML

Häufige Fehler & Quick Wins

Top 10 Accessibility-Fehler

  1. Fehlende alt-Texte bei Bildern (90% aller Websites)

    • Fix: <img alt="Beschreibung">
  2. Unzureichender Farbkontrast (85%)

    • Fix: WebAIM Contrast Checker nutzen
  3. Fehlende Form-Labels (70%)

    • Fix: <label for="input-id">
  4. Nicht-tastaturzugängliche Elemente (65%)

    • Fix: <button> statt <div onclick>
  5. Überschriften-Hierarchie falsch (60%)

    • Fix: h1 → h2 → h3 (keine Sprünge)
  6. Links ohne aussagekräftigen Text (55%)

    • Fix: “Mehr erfahren” → “Mehr über BFSG erfahren”
  7. Fehlende ARIA-Labels bei Icons (50%)

    • Fix: <button aria-label="Suchen">
  8. Videos ohne Untertitel (85%)

    • Fix: WebVTT-Dateien erstellen
  9. Fokus-Indikator entfernt (40%)

    • Fix: NIEMALS outline: none ohne Alternative
  10. Leere Links/Buttons (35%)

    • Fix: Sichtbarer Text oder aria-label

Quick Wins (unter 1 Stunde)

Alt-Texte ergänzen:

# Alle Bilder ohne alt finden
grep -r "<img" . | grep -v "alt="

Skip-Link hinzufügen (5 Minuten):

<a href="#main" class="skip-link">Zum Hauptinhalt</a>

Semantic HTML (30 Minuten):

  • Ersetze <div class="header"><header>
  • Ersetze <div class="nav"><nav>
  • Ersetze <div class="main"><main>

Fokus-Styles (10 Minuten):

:focus-visible {
  outline: 3px solid #0066cc;
  outline-offset: 2px;
}

Ressourcen & Weiterführendes

Offizielle Standards

Testing-Tools

Automatisiert:

Manuell:

Kontrast-Checker:

Checklisten

Fazit: BFSG-Konformität ist machbar

Die technische Umsetzung des BFSG erfordert systematisches Vorgehen, aber keine Raketenwissenschaft:

Die 5 Kern-Prinzipien

  1. Semantisches HTML - Nutze <header>, <nav>, <main>, <button>
  2. Tastaturnavigation - Alles muss ohne Maus bedienbar sein
  3. Alternative Texte - Beschreibe alle visuellen Inhalte
  4. Ausreichender Kontrast - Mindestens 4.5:1 für Text
  5. Testen, testen, testen - Automatisiert + manuell mit Screen Reader

Ihr Weg zur BFSG-Konformität

Bis 28. Juni 2025 müssen Sie handeln:

  1. Phase 1 (Jetzt - Januar 2025): Ist-Analyse mit automatisierten Tools
  2. Phase 2 (Februar - März 2025): Quick Wins umsetzen (alt-Texte, Kontraste, Semantik)
  3. Phase 3 (April - Mai 2025): Komplexe Anpassungen (ARIA, Formulare, Videos)
  4. Phase 4 (Juni 2025): Testing & Dokumentation

Benötigen Sie Unterstützung?

Wendermedia ist BFSG-spezialisiert und unterstützt Sie bei der technischen Umsetzung:

Unsere BFSG-Services

BFSG Compliance Audit (980€)

  • Automatisierte Tests (axe, Pa11y, Lighthouse)
  • Manuelle Screen Reader Tests
  • Detaillierter Report mit Handlungsempfehlungen
  • Priorisierte To-Do-Liste

BFSG Technische Umsetzung (ab 4.000€)

  • Semantisches HTML-Refactoring
  • ARIA-Integration
  • Tastaturnavigation optimieren
  • Kontrast-Anpassungen
  • Testing & Dokumentation

BFSG Entwickler-Schulung (1.200€/Tag)

  • Team-Workshop (4-8h)
  • Best Practices & Code-Reviews
  • Testing-Workflows einrichten
  • Laufender Support

Jetzt BFSG-Audit anfragen

Deadline 28. Juni 2025 - Handeln Sie jetzt!

📞 Kostenlose BFSG-Erstberatung buchen

Oder rufen Sie direkt an: +49 345 2470 0940


Autor: Arnold Wender, Webdesign & BFSG-Spezialist aus Halle (Saale)

Letzte Aktualisierung: November 2025