TechnologieProgrammierung

Automatisierte Barrierefreiheitsprüfung für viele Websites

netcomputing.de Redaktion26. August 202610 Min. Lesezeit

Zusammenfassung

Wer mehrere Websites betreibt, kann nicht bei jeder Änderung eine Fachperson für eine manuelle Barrierefreiheitsprüfung buchen. axe-core von Deque findet automatisiert im Schnitt 57 Prozent der WCAG-Probleme und lässt sich über @axe-core/playwright in eine GitHub-Actions-Pipeline einbauen. Der Build schlägt nur bei kritischen und schwerwiegenden Verstößen fehl, kleinere Funde werden nur protokolliert. Screenreader- und Tastaturtests bleiben trotzdem nötig, weil axe-core Alt-Text nur auf Vorhandensein prüft.

Eine Organisation mit vierzig eigenständig gepflegten Websites kann nicht vor jeder Veröffentlichung eine Fachperson für eine manuelle Prüfung nach den Web Content Accessibility Guidelines (WCAG) buchen. Trotzdem gilt die Pflicht unabhängig von der Betriebsgröße: Seit dem 28. Juni 2025 verlangt die Richtlinie (EU) 2019/882, bekannt als European Accessibility Act, von Herstellern, Diensteanbietern, Importeuren und Händlern bestimmter Produkte und Dienstleistungen barrierefreie digitale Angebote. Die Mitgliedstaaten setzen die Vorgabe mit eigenen Bußgeldern und teils mit Marktrücknahmen durch. Ein manueller Rundgang durch jede Seite jeder Website lässt sich bei dieser Menge an Adressen nicht regelmäßig wiederholen, selbst wenn das nötige Budget vorhanden wäre. Automatisierung wird damit zur einzig praktikablen Antwort.

axe-core setzt genau an dieser Stelle an. Die quelloffene Prüf-Engine des Herstellers Deque steckt bereits in den Chrome-DevTools, in Lighthouse und in zahlreichen Testframeworks, aktuell in Version 4.13.0 vom 5. August 2026. Über die Bindung @axe-core/playwright lässt sie sich in einen echten Playwright-Test einbauen und in der Continuous-Integration-Pipeline (CI), also der automatisierten Kette aus Test- und Buildschritten bei jedem Codewechsel, gegen jede Seite jeder betreuten Website laufen lassen, lange bevor ein Mensch die Seite überhaupt öffnet. Was das Werkzeug dabei zuverlässig findet und was es bewusst offen lässt, entscheidet darüber, wie ein solcher Aufbau in der Praxis aussehen muss.

Systemvoraussetzungen

Ein Aufbau für viele Websites gleichzeitig braucht wenige, aber aktuelle Bausteine. Die folgende Tabelle nennt sie mit der Version, die zum Zeitpunkt dieses Artikels aktuell ist.

KomponenteVersion oder AnforderungZweck
axe-coreVersion 4.13.0, veröffentlicht am 5. August 2026Regel-Engine, die den gerenderten DOM nach WCAG-Mustern durchsucht
@axe-core/playwrightVersion 4.13.0, folgt der Versionsnummer von axe-coreBindung, die axe-core über die Klasse AxeBuilder in einen Playwright-Test einspeist
@playwright/testab Version 1.62, Node.js in einer aktuell unterstützten Version (22, 24 oder 26)Test-Runner, der den Browser steuert und die Seite lädt
GitHub Actions Checkoutactions/checkout@v4 oder neuerHolt den Code in der Pipeline, Grundlage für jeden Testlauf
WCAG-Tag-Auswahlzum Beispiel wcag2a, wcag2aa, wcag21aaLegt fest, gegen welche Konformitätsstufe axe-core prüft
Pflicht-Statuscheckim Repository für den Zielzweig hinterlegtVerhindert, dass ein fehlgeschlagener Scan trotzdem gemergt wird

Systemarchitektur

Ein Verstoß ist in diesem Zusammenhang jede Stelle im gerenderten HTML, die eine automatisiert prüfbare WCAG-Regel verletzt: ein Bild ohne Alt-Attribut, ein Formularfeld ohne zugehöriges Label, eine Überschriftenebene, die eine Stufe überspringt, oder ein Text, dessen Kontrast zum Hintergrund unter dem geforderten Verhältnis liegt. axe-core selbst startet keinen eigenen Browser, sondern läuft als JavaScript innerhalb der bereits geladenen Seite und durchsucht von dort aus den Document Object Model (DOM), also die Baumstruktur, in die ein Browser eine Webseite beim Rendern übersetzt. Die Bindung @axe-core/playwright übernimmt das Einschleusen: Sie öffnet die Seite mit Playwright, fügt das axe-core-Skript ein und liest über dessen zentrale Methode analyze() das Ergebnis wieder aus. Von Hand geht das bei vierzig Websites nicht.

flowchart TD
    A[Playwright oeffnet eine Seite der Website] --> B[AxeBuilder injiziert axe-core in die Seite]
    B --> C[axe-core durchsucht den gerenderten DOM]
    C --> D[Die Methode analyze sammelt jeden Verstoss mit seiner Impact-Stufe]
    D --> E{Ist die Impact-Stufe kritisch oder schwerwiegend}
    E -->|Ja| F[Der CI-Job schlaegt fehl und blockiert den Merge]
    E -->|Nein| G[Der Verstoss wird nur protokolliert]
    F --> H[Die zustaendige Person behebt den Verstoss]
    G --> I[Der Bericht steht im Pull Request]
    H --> J[Der naechste Lauf prueft die Seite erneut]
    I --> J

Der Ablauf trennt zwei Entscheidungen, die sonst leicht vermischt werden. Erstens: Welche Regeln überhaupt laufen, gesteuert über die WCAG-Stufen, die withTags() auswählt. Zweitens: Welcher Fund den Build stoppt, gesteuert über die Impact-Stufe, die axe-core jedem Verstoß automatisch mitgibt: critical, serious, moderate oder minor. Ein Kontrastfehler auf einer selten besuchten Unterseite durchläuft dieselbe Regelprüfung wie ein fehlendes Formular-Label auf der Startseite, aber nicht dieselbe Konsequenz für den Merge.

Schritt-für-Schritt-Umsetzung

Playwright-Test mit axe-core einrichten

Der erste Schritt bindet axe-core in einen normalen Playwright-Test ein. Die Bindung @axe-core/playwright installiert sich wie jedes andere Testpaket und stellt die Klasse AxeBuilder bereit, die eine bereits geöffnete Playwright-Seite entgegennimmt.

npm install --save-dev @axe-core/playwright @playwright/test
import { test, expect } from '@playwright/test';
import { AxeBuilder } from '@axe-core/playwright';

test('Startseite verletzt keine kritischen WCAG-Regeln', async ({ page }) => {
  await page.goto('https://www.beispiel-domain.de/');

  const ergebnis = await new AxeBuilder({ page }).analyze();

  console.log(ergebnis.violations.length, 'automatisiert pruefbare Befunde insgesamt');
  expect(ergebnis.violations).toEqual([]);
});

Dieser erste Test ist bewusst noch grob: Er wertet jeden gefundenen Verstoß gleich, unabhängig von dessen Schwere. Für den produktiven Einsatz braucht es zwei Verfeinerungen, die die nächsten beiden Schritte liefern.

WCAG-Stufen mit withTags auswählen

Die Methode withTags() schränkt den Scan auf die Regeln ein, die zu bestimmten WCAG-Konformitätsstufen gehören. axe-core kennt dafür feste Bezeichner: wcag2a und wcag2aa für WCAG 2.0, wcag21a und wcag21aa für die Ergänzungen aus WCAG 2.1, dazu wcag22aa für WCAG 2.2 sowie best-practice für Regeln ohne direkten WCAG-Bezug. Für die meisten Organisationen ist die Kombination aus Stufe A und AA die richtige Wahl, weil die europäische Norm EN 301 549 für Webinhalte genau diese Konformitätsstufe WCAG 2.1 AA vorgibt und damit die technische Richtschnur für den European Accessibility Act bildet. Zusätzlich lassen sich mit include() und exclude() einzelne Bereiche der Seite gezielt ein- oder ausschließen, etwa um ein eingebettetes Drittanbieter-Widget aus der eigenen Verantwortung herauszuhalten.

const ergebnis = await new AxeBuilder({ page })
  .include('main')
  .exclude('.drittanbieter-widget')
  .withTags(['wcag2a', 'wcag2aa', 'wcag21aa'])
  .analyze();

Build nur bei kritischen Verstößen stoppen

Jeder von axe-core gemeldete Verstoß trägt ein Feld namens impact mit einem von vier Werten: critical für Fehler, die eine Kernfunktion komplett blockieren, serious für Fehler, die die Nutzung erheblich erschweren, sowie moderate und minor für Fälle mit spürbar geringerer Auswirkung. Ein CI-Gate, das jeden Fund gleich behandelt, blockiert Merges schon wegen kleinerer Funde. Das Team ignoriert es sonst. Sinnvoller ist ein Filter, der nur bei critical und serious fehlschlägt und den Rest lediglich protokolliert.

const alleBefunde = ergebnis.violations;
const kritisch = alleBefunde.filter(
  (verstoss) => verstoss.impact === 'critical' || verstoss.impact === 'serious'
);
const restliche = alleBefunde.filter(
  (verstoss) => verstoss.impact === 'moderate' || verstoss.impact === 'minor'
);

if (restliche.length > 0) {
  console.warn(restliche.length, 'nicht blockierende Befunde, siehe Testbericht');
}

expect(kritisch).toEqual([]);

Alle Seiten aller Websites per Matrix scannen

Ein einzelner Test gegen eine einzelne Startseite deckt bei vierzig eigenständigen Websites nur einen Bruchteil der tatsächlichen Fläche ab. GitHub Actions löst das über eine Matrix-Strategie: Ein Job läuft dabei einmal je Eintrag in einer Liste, hier je betreuter Website, wobei jeder Lauf unabhängig von den anderen startet und im Ergebnis einzeln angezeigt wird.

name: accessibility-scan
on:
  pull_request:
  push:
    branches: [main]
  schedule:
    - cron: "0 5 * * 1"

jobs:
  axe-scan:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        website: [website-a, website-b, website-c]
    defaults:
      run:
        working-directory: sites/${{ matrix.website }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npx playwright install --with-deps chromium
      - run: npx playwright test tests/a11y.spec.ts

Der Workflow läuft bei jedem Pull Request, zusätzlich bei jedem Push auf den Hauptzweig und einmal wöchentlich nach Zeitplan, damit ein neu gefundener Verstoß nicht allein von einer laufenden Codeänderung abhängt. fail-fast: false sorgt dafür, dass ein fehlgeschlagener Scan bei einer Website die Prüfung der übrigen nicht abbricht, sodass ein einziger Pull Request am Ende den vollständigen Zustand aller Websites zeigt.

Häufige Fehlerquellen

  • Alt-Text ist vorhanden, aber nichtssagend. axe-core meldet ein Bild mit dem Attribut alt="bild1" nicht als Fehler, weil die zugehörige Regel nur prüft, ob das Attribut existiert, nicht, ob sein Inhalt das Bild beschreibt. Fix: den Alt-Text bei jeder Bildänderung stichprobenartig gegen das Bild lesen, unabhängig vom automatisierten Ergebnis.
  • Ausgeblendete Bereiche bleiben ungeprüft. Ein Navigationsmenü, das erst nach einem Klick sichtbar wird, oder ein Dialog, der im Ruhezustand der Seite ausgeblendet ist, taucht im Scan nicht auf, weil axe-core nur den DOM zum Zeitpunkt von analyze() durchsucht. Fix: den jeweiligen Zustand im Test gezielt öffnen und dafür einen eigenen Aufruf von analyze() schreiben.
  • Der Build stoppt bei jedem Fund statt nur bei schweren. Ein Vergleich von violations direkt gegen ein leeres Array blockiert einen Merge schon wegen eines einzelnen minor-Befundes. Fix: ausschließlich nach critical und serious filtern und den Rest in den Testbericht schreiben.
  • Das incomplete-Ergebnis bleibt ungelesen. Neben violations liefert axe-core ein zweites Feld namens incomplete für Elemente, bei denen sich ein Verstoß nicht sicher feststellen ließ. Wer nur violations auswertet, übersieht ausgerechnet die Fälle, die eine manuelle Prüfung am nötigsten haben. Fix: incomplete regelmäßig durchsehen, auch wenn es den Build nicht stoppt.
  • Dynamischer Inhalt ist beim Scan noch nicht geladen. Läuft analyze() unmittelbar nach page.goto(), bevor nachgeladene Inhalte oder ein Cookie-Banner vollständig gerendert sind, prüft axe-core einen unvollständigen Zustand der Seite. Fix: vor dem Scan gezielt auf ein Element warten, statt sich auf eine feste Wartezeit zu verlassen.
  • Nur die Startseite jeder Website steht im Test. Bei vierzig Websites mit je einer geprüften Seite bleiben hunderte Unterseiten ungeprüft, obwohl Formulare und Navigationselemente dort oft abweichen. Fix: pro Website eine Liste der wichtigsten Routen pflegen und jede Route einzeln in der Matrix oder einer Schleife prüfen.

Häufig gestellte Fragen

Wie viel Prozent der WCAG-Probleme erkennt axe-core automatisch?

axe-core erkennt nach einer eigenen Auswertung seines Herstellers Deque im Schnitt 57 Prozent aller Barrierefreiheitsprobleme automatisch. Die Zahl stammt aus einer Analyse von mehr als 13.000 geprüften Seiten und knapp 300.000 gefundenen Einzelproblemen aus echten Erstprüfungen. Für Fälle, bei denen sich ein Verstoß nicht sicher feststellen lässt, liefert axe-core zusätzlich ein incomplete-Ergebnis, das eine manuelle Prüfung verlangt, statt einen falschen Fehlalarm auszugeben. Die verbleibenden gut 40 Prozent betreffen vor allem Kriterien, die ein Urteil erfordern, etwa ob eine Beschreibung inhaltlich verständlich ist oder eine Screenreader-Ansage tatsächlich Sinn ergibt.

Kann ein automatisierter axe-core-Scan eine manuelle Barrierefreiheitsprüfung ersetzen?

Ein automatisierter axe-core-Scan kann eine manuelle Barrierefreiheitsprüfung nicht ersetzen, weil er nur Kriterien bewerten kann, die sich rein aus dem Code ableiten lassen. axe-core stellt fest, ob ein Bild ein Alt-Attribut trägt, aber nicht, ob dessen Text das Bild inhaltlich zutreffend beschreibt, und es beurteilt nicht, ob eine reine Tastaturbedienung in einer sinnvollen Reihenfolge durch die Seite führt. Ein Screenreader-Test und eine Prüfung mit ausschließlicher Tastaturbedienung bleiben deshalb Teil jeder ernsthaften Barrierefreiheitsprüfung, besonders bei Formularen, Menüs und Dialogen. Der automatisierte Scan übernimmt dafür die laufende Kontrolle bei jeder einzelnen Änderung, statt nur bei einem jährlichen Audit zu greifen.

Wie stoppt man den CI-Build nur bei kritischen Barrierefreiheitsfehlern?

Der CI-Build stoppt nur bei kritischen Barrierefreiheitsfehlern, wenn die Auswertung die von axe-core gemeldeten Verstöße nach ihrer Impact-Stufe filtert, statt jeden Fund gleich zu behandeln. axe-core vergibt jedem Verstoß eine von vier Stufen: critical, serious, moderate oder minor. Ein Test wertet ausschließlich die ersten beiden Stufen als Fehlschlag aus und schreibt den Rest in den Testbericht, ohne den Merge zu blockieren. So bleibt die Pflichtprüfung streng bei Verstößen, die die Bedienung tatsächlich verhindern, ohne dass ein Team wegen einer Formsache jede Woche einen roten Build ignoriert.

Ab wann gilt die europäische Pflicht zur digitalen Barrierefreiheit für Websites?

Die europäische Pflicht zur digitalen Barrierefreiheit gilt seit dem 28. Juni 2025 für neue Produkte und Dienstleistungen, die unter die Richtlinie (EU) 2019/882 fallen, bekannt als European Accessibility Act. Betroffen sind unter anderem Hersteller, Diensteanbieter, Importeure und Händler in Bereichen wie E-Commerce, Bankdienstleistungen, E-Books und der Fahrgastinformation im Personenverkehr, unabhängig davon, in welchem Land das Unternehmen seinen Sitz hat. Als technische Richtschnur gilt in der Praxis die Norm EN 301 549, die für Webinhalte die Konformitätsstufe WCAG 2.1 AA festlegt. Jeder Mitgliedstaat setzt die Richtlinie mit eigenen Fristen, Kontrollen und Bußgeldern durch, weshalb eine verbindliche Einschätzung der eigenen Pflichten eine fachkundige rechtliche Prüfung im Einzelfall braucht.

Quellen

  1. axe-core Repository: Funktionsumfang, Version und Testabdeckung, Deque Systems (GitHub), abgerufen am 2026-08-26
  2. axe-core Release v4.13.0, Deque Systems (GitHub), abgerufen am 2026-08-26
  3. The Automated Accessibility Coverage Report (57-Prozent-Studie), Deque Systems, abgerufen am 2026-08-26
  4. @axe-core/playwright: AxeBuilder-API mit analyze, include, exclude, withTags, Deque Systems (GitHub), abgerufen am 2026-08-26
  5. axe-core API-Dokumentation: Impact-Stufen und WCAG-Tags, Deque Systems (GitHub), abgerufen am 2026-08-26
  6. EN 301 549 als technische Richtschnur des European Accessibility Act, Deque Systems, abgerufen am 2026-08-26
  7. European Accessibility Act: Geltungsbereich und Stichtag 28. Juni 2025, Davis Wright Tremaine, abgerufen am 2026-08-26

Der Content wurde mit Hilfe von KI erstellt, vor allem in der Recherche und Vorformulierung. Prüfung und Abnahme durch unsere Redaktion.