Web-Zugänglichkeit (a11y) in Cursor: WCAG, ARIA und axe-core

Web-Zugänglichkeit (a11y) stellt sicher, dass jeder, einschließlich Menschen mit Behinderungen, Ihre Anwendung wahrnehmen, verstehen und mit ihr interagieren kann. Cursor, ein KI-gestützter IDE-Editor, beschleunigt die zugängliche Entwicklung durch das Generieren ARIA-konformer Auszeichnung, das Ausführen automatisierter Audits und das Anwenden von WCAG-Korrekturen in Ihrer gesamten Codebasis. Dieser Leitfaden behandelt ARIA-Labels, WCAG-Konformität, axe-core-Tests, KI-gestützte a11y-Korrekturen und Screenreader-Tests.
Voraussetzungen
Bevor Sie beginnen, stellen Sie sicher, dass Sie Folgendes haben:
- Cursor (neueste Version empfohlen) als IDE-Editor
- Ein Web-Projekt (React, Vue oder einfaches HTML und JavaScript)
- Node.js 18 oder höher für die Test-Tools
- Grundlegende Vertrautheit mit HTML-Semantik
Zugänglichkeit ist deutlich günstiger, sie von Anfang an einzubauen, als sie nachzurüsten. Öffnen Sie Ihr Projekt von Anfang an in Cursor und lassen Sie die KI Komponenten auditeren, während Sie sie schreiben. Das Korrigieren eines fehlenden Labels während der Entwicklung dauert Sekunden; das Korrigieren desselben Problems in einer Produktions-App dauert Wochen.
WCAG-Konformität verstehen
Die Web Content Accessibility Guidelines (WCAG) definieren, wie man Web-Inhalte zugänglich macht. Sie sind um vier Prinzipien herum organisiert, oft POUR genannt:
- Wahrnehmbar: Informationen und Benutzeroberflächenkomponenten müssen für Benutzer wahrnehmbar präsentiert werden.
- Bedienbar: Benutzeroberflächenkomponenten und Navigation müssen bedienbar sein.
- Verständlich: Inhalt und Bedienung der Benutzeroberfläche müssen verständlich sein.
- Robust: Inhalt muss robust genug sein, um von Hilfstechnologien interpretiert zu werden.
WCAG definiert drei Konformitätsstufen: A (Minimum), AA (das rechtliche Ziel für die meisten Organisationen) und AAA (erweitert). Bitten Sie Cursor, die Stufe-AA-Anforderungen für eine bestimmte Funktion zusammenzufassen:
Liste die WCAG 2.2 Stufe-AA-Erfolgskriterien auf, die auf ein
mehrstufiges Checkout-Formular mit Datumsauswahlen und
Kreditkarteneingaben zutreffen.
Cursor gibt die relevanten Kriterien zurück und erklärt, wie jedes mit konkreten Code-Vorschlägen erfüllt wird.
Grundlagen des semantischen HTML
Semantisches HTML ist die Grundlage der Zugänglichkeit. Das richtige Element entfernt oft die Notwendigkeit für ARIA vollständig. Cursor hilft Ihnen, die richtige Auszeichnung zu wählen und zu generieren.
Semantische Komponenten generieren
Bitten Sie Cursor, eine Navigationsleiste mit integrierter Zugänglichkeit zu erstellen:
Erstelle eine responsive Website-Navigation in React, die:
- Ein <nav>-Landmark mit einem zugänglichen Namen verwendet
- Einen Skip-Link am Anfang der Seite hat
- Ein mobiles Menü mit aria-expanded und aria-controls umschaltet
- Bei Escape schließt und den Fokus auf die Umschalttaste zurückgibt
- Vollständige Tastaturnavigation unterstützt
Cursor generiert die Komponente:
import { useState, useRef, useEffect } from 'react';
export function SiteNav({ links }: { links: { href: string; label: string }[] }) {
const [open, setOpen] = useState(false);
const toggleRef = useRef<HTMLButtonElement>(null);
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
setOpen(false);
toggleRef.current?.focus();
}
};
document.addEventListener('keydown', onKey);
return () => document.removeEventListener('keydown', onKey);
}, [open]);
return (
<>
<a href="#main" className="skip-link">Zum Hauptinhalt springen</a>
<nav aria-label="Hauptnavigation">
<button
ref={toggleRef}
aria-expanded={open}
aria-controls="mobile-menu"
onClick={() => setOpen((v) => !v)}
>
Menü
</button>
<ul id="mobile-menu" hidden={!open}>
{links.map((link) => (
<li key={link.href}>
<a href={link.href}>{link.label}</a>
</li>
))}
</ul>
</nav>
</>
);
}
Die erste Regel von ARIA lautet: Verwenden Sie kein ARIA, wenn ein natives HTML-Element existiert. Ein echtes <button> bietet Ihnen Tastaturfokus, Enter- und Space-Aktivierung und Screenreader-Semantik kostenlos. Bitten Sie Cursor: "Ersetze diesen div-basierten Button durch einen semantischen Button", wann immer Sie onClick auf einem nicht-interaktiven Element sehen.
ARIA-Labels und Rollen
Wenn natives HTML die Semantik, die Sie benötigen, nicht ausdrücken kann, füllt ARIA die Lücke. Cursor generiert korrekte ARIA-Attribute und warnt vor häufigen Fehlern.
Zugängliche Formulare
Formulareingaben benötigen Labels. Bitten Sie Cursor, ein zugängliches Formularfeld zu generieren:
Erstelle eine wiederverwendbare FormField-Komponente mit:
- Einem zugehörigen <label> unter Verwendung von htmlFor
- Einem aria-required-Attribut, wenn erforderlich
- Einem aria-describedby-Link zu Hilfs- und Fehlertext
- Fehlermeldungen mit role="alert"
import { useId } from 'react';
interface FormFieldProps {
label: string;
name: string;
type?: string;
required?: boolean;
error?: string;
helper?: string;
}
export function FormField({ label, name, type = 'text', required, error, helper }: FormFieldProps) {
const fieldId = useId();
const helperId = `${fieldId}-helper`;
const errorId = `${fieldId}-error`;
const describedBy = [helper && helperId, error && errorId].filter(Boolean).join(' ') || undefined;
return (
<div>
<label htmlFor={fieldId}>
{label}
{required && <span aria-hidden="true">*</span>}
</label>
<input
id={fieldId}
name={name}
type={type}
required={required}
aria-required={required}
aria-describedby={describedBy}
aria-invalid={!!error}
/>
{helper && !error && (
<p id={helperId} className="helper-text">{helper}</p>
)}
{error && (
<p id={errorId} role="alert" className="error-text">{error}</p>
)}
</div>
);
}
Live-Regionen für dynamische Updates
Wenn sich Inhalte dynamisch aktualisieren (Benachrichtigungen, Suchergebnisse), benötigen Screenreader eine Live-Region, um Änderungen anzukündigen. Cursor generiert das Muster:
export function SearchResults({ query, results }: { query: string; results: string[] }) {
return (
<div
aria-live="polite"
aria-atomic="true"
role="status"
>
{results.length === 0 ? (
<p>Keine Ergebnisse für "{query}".</p>
) : (
<p>{results.length} Ergebnisse gefunden für "{query}".</p>
)}
<ul>
{results.map((r) => <li key={r}>{r}</li>)}
</ul>
</div>
);
}
Verwenden Sie aria-live="polite" für nicht dringende Updates und aria-live="assertive" nur für kritische Warnungen. Der übermäßige Gebrauch von assertiven Live-Regionen unterbricht Screenreader-Benutzer ständig und macht Ihre App unbenutzbar. Verwenden Sie niemals role="alert" für Erfolgsmeldungen; reservieren Sie es für tatsächliche Fehler, die sofortige Aufmerksamkeit erfordern.
Automatisierte Tests mit axe-core
Automatisierte Tools erkennen etwa 30 bis 40 Prozent der Zugänglichkeitsprobleme. axe-core ist der Industriestandard. Cursor kann es in Ihre Test-Suite und CI-Pipeline integrieren.
axe-core mit Jest einrichten
Bitten Sie Cursor, automatisierte Zugänglichkeitstests hinzuzufügen:
Füge axe-core zu meinem React-Projekt hinzu. Erstelle einen Jest-Test,
der die SiteNav-Komponente mit Testing Library rendert und axe-Regeln
ausführt.
Cursor installiert die Abhängigkeiten und schreibt den Test:
npm install -D @axe-core/react axe-core jest-axe @testing-library/react @testing-library/jest-dom
// src/components/SiteNav.test.tsx
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import { SiteNav } from './SiteNav';
expect.extend(toHaveNoViolations);
const links = [
{ href: '/', label: 'Startseite' },
{ href: '/about', label: 'Über uns' },
];
describe('SiteNav', () => {
it('hat keine Zugänglichkeitsverletzungen wenn geschlossen', async () => {
const { container } = render(<SiteNav links={links} />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
it('hat keine Zugänglichkeitsverletzungen wenn geöffnet', async () => {
const { container, getByText } = render(<SiteNav links={links} />);
getByText('Menü').click();
const results = await axe(container);
expect(results).toHaveNoViolations();
});
});
Wiederverwendbarer axe-Test-Helfer
Cursor kann einen wiederverwendbaren Helfer generieren, damit jeder Komponententest konsistent bleibt:
import { render } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
export async function expectAccessible(component: React.ReactElement) {
const { container } = render(component);
const results = await axe(container, {
rules: {
// Deaktivieren Sie Regeln, die Sie woanders absichtlich behandeln
region: { enabled: false },
},
});
expect(results).toHaveNoViolations();
return results;
}
Verwenden Sie ihn in jedem Komponententest:
import { expectAccessible } from '../test/expectAccessible';
import { FormField } from './FormField';
it('ist zugänglich', async () => {
await expectAccessible(<FormField label="E-Mail" name="email" required />);
});
Führen Sie die vollständige axe-Suite vor jedem Commit mit einem npm-Skript aus. Bitten Sie Cursor: "Füge ein a11y-Skript zu package.json hinzu, das alle axe-Tests ausführt und bei Verstößen fehlschlägt." Dies verhindert, dass Regressionen jemals Ihren Hauptzweig erreichen.
KI-gestützte Zugänglichkeitskorrekturen
Die KI von Cursor kann eine gesamte Komponentendatei scannen, Zugänglichkeitsprobleme finden und Korrekturen in einem Durchgang anwenden. Dies ist einer der wertvollsten a11y-Workflows.
Auditing einer Komponente
Öffnen Sie eine Komponente in Cursor und führen Sie diesen Prompt im KI-Chat aus:
Auditiere diese Komponente auf WCAG 2.2 AA-Konformität. Liste jedes
Problem mit der Zeilennummer auf, erkläre, warum es fehlschlägt, und
schreibe den Code mit Korrekturen neu. Füge Kommentare hinzu, die
jede Änderung erklären.
Cursor könnte melden:
- Zeile 12:
<div onClick>ist nicht per Tastatur zugänglich. Durch<button>ersetzen. - Zeile 20:
<img>hat keinalt-Attribut. Beschreibenden Alt-Text hinzufügen. - Zeile 28: Der Farbkontrast beträgt 3.1:1, unter dem Minimum von 4.5:1 für normalen Text.
- Zeile 35: Der modale Dialog hat keine Fokusfalle. Benutzer können hinter den Dialog tabben.
Cursor wendet dann die Korrekturen an:
// Vorher
<div className="card" onClick={openDetails}>
<img src={product.image} />
<h3 style={{ color: '#999' }}>{product.name}</h3>
</div>
// Nachher
<button
className="card"
onClick={openDetails}
aria-label={`Details für ${product.name} ansehen`}
>
<img src={product.image} alt={`${product.name} Produktfoto`} />
<h3 style={{ color: '#595959' }}>{product.name}</h3>
</button>
Fokusfalle generieren
Modale und Dialoge benötigen eine Fokusfalle, damit Tastaturbenutzer nicht durch Tabben aus dem Dialog entkommen können. Bitten Sie Cursor:
Füge eine Fokusfalle zu dieser Modal-Komponente hinzu. Bewege den
Fokus beim Öffnen zum ersten fokussierbaren Element, fange Tab und
Shift+Tab im Dialog ein und gib den Fokus beim Schließen an den
Auslöser-Button zurück.
import { useEffect, useRef } from 'react';
const FOCUSABLE = 'a[href], button:not([disabled]), input, textarea, select, [tabindex]:not([tabindex="-1"])';
export function useFocusTrap(active: boolean) {
const containerRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (!active || !containerRef.current) return;
const container = containerRef.current;
const elements = container.querySelectorAll<HTMLElement>(FOCUSABLE);
if (elements.length === 0) return;
const first = elements[0];
const last = elements[elements.length - 1];
first.focus();
const onKey = (e: KeyboardEvent) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
};
container.addEventListener('keydown', onKey);
return () => container.removeEventListener('keydown', onKey);
}, [active]);
return containerRef;
}
Eine Fokusfalle ist bedeutungslos, wenn das zugrunde liegende HTML nicht per Tastatur zugänglich ist. Die Falle verwaltet nur Elemente, die tatsächlich fokussierbar sind. Wenn Ihr Dialog nur <div>-Elemente mit onClick-Handlern enthält, hat die Fokusfalle nichts zu fokussieren. Kombinieren Sie die Falle immer mit semantischen, fokussierbaren Elementen.
Screenreader-Tests
Automatisierte Tests erkennen strukturelle Probleme, aber nur manuelle Tests mit einem Screenreader offenbaren die erlebte Erfahrung. Cursor kann Testskripte und Checklisten generieren.
Checkliste für reine Tastaturtests
Bitten Sie Cursor, eine Tastaturtest-Checkliste zu generieren:
Erstelle eine Checkliste für reine Tastaturtests für eine Web-Anwendung,
die Navigation, Formulare, Widgets und dynamische Inhalte abdeckt.
Cursor produziert:
- Tabben Sie durch die Seite in logischer Reihenfolge ohne Fallen.
- Der Skip-Link ist das erste fokussierbare Element und springt zum Hauptinhalt.
- Alle interaktiven Elemente sind mit Tab und Shift+Tab erreichbar.
- Benutzerdefinierte Widgets (Tabs, Akkordeons) unterstützen Pfeiltasten und Pos1/Ende.
- Modale fangen den Fokus ein und geben ihn beim Schließen an den Auslöser zurück.
- Ein sichtbarer Fokusindikator ist auf jedem fokussierbaren Element vorhanden.
- Enter und Space aktivieren Buttons; Enter aktiviert Links.
- Formulare werden mit Enter auf dem Absenden-Button abgesendet.
Testen mit NVDA, JAWS und VoiceOver
Cursor kann Testnotizen für jeden Screenreader generieren:
Schreibe einen Schnellstart-Leitfaden zum Testen meiner App mit NVDA
auf Windows, VoiceOver auf macOS und TalkBack auf Android. Schließe
die Verknüpfung zum Starten jedes Lesers ein und wie man nach
Überschrift und Landmark navigiert.
Cursor gibt eine Vergleichstabelle und einen Navigations-Spickzettel zurück, den Sie als Referenzdatei in Ihrem Projekt speichern können.
Farbkontrast und visuelles Design
Visuelle Zugänglichkeit ist Teil des WCAG-Bildes. Zu geringer Kontrast ist eines der häufigsten Probleme.
Kontrast mit KI prüfen
Bitten Sie Cursor, Ihre Design-Tokens zu evaluieren:
Hier sind meine Farb-Tokens in tailwind.config.js. Prüfe jedes Text-
und Hintergrundpaar gegen WCAG-AA-Kontrastverhältnisse (4.5:1 für
normalen Text, 3:1 für großen Text). Markiere Fehler und schlage
Korrekturen vor.
Cursor liest die Konfiguration, berechnet die Kontrastverhältnisse und meldet Fehler:
// tailwind.config.js-Tokens, die AA nicht bestehen
// text-gray-400 auf bg-white: 2.85:1 — FEHLER
// Korrektur: text-gray-600 (#4B5563) für 7.21:1 verwenden
Cursor aktualisiert die Konfiguration:
module.exports = {
theme: {
extend: {
colors: {
'text-secondary': '#4B5563', // war #9CA3AF, besteht jetzt AA
},
},
},
};
Verlassen Sie sich niemals allein auf Farbe, um Bedeutung zu vermitteln. Ein roter Rand um ein ungültiges Feld ist für farbenblinde Benutzer, die ebenfalls auf Screenreader angewiesen sind, unsichtbar. Kombinieren Sie Farbe immer mit Text oder einem Symbol. Bitten Sie Cursor: "Füge Text und Symbole hinzu, um Fehlerzustände neben Farbe zu vermitteln", um die Korrektur in einem gesamten Formular vorzunehmen.
Zugänglichkeit in CI
Automatisierte a11y-Prüfungen gehören in Ihre Continuous-Integration-Pipeline. Cursor kann die Konfiguration generieren.
Lighthouse CI mit a11y-Kategorie
Bitten Sie Cursor, Lighthouse CI hinzuzufügen:
Füge Lighthouse CI zu meinem GitHub-Actions-Workflow mit aktivierter
Zugänglichkeitskategorie und einer Mindestpunktzahl von 0.9 hinzu.
# .github/workflows/lighthouse.yml
name: Lighthouse
on: [pull_request]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm run build
- name: Run Lighthouse
uses: treosh/lighthouse-ci-action@v11
with:
urls: |
http://localhost:3000
uploadArtifacts: true
configPath: .lighthouserc.json
// .lighthouserc.json
{
"ci": {
"assert": {
"assertions": {
"categories:accessibility": ["error", { "minScore": 0.9 }]
}
},
"collect": {
"startServerCommand": "npm run start",
"startServerReadyPattern": "ready",
"numberOfRuns": 3
}
}
}
Zusammenfassung der Best Practices
Beachten Sie diese Prinzipien beim Erstellen zugänglicher Apps in Cursor:
- Bevorzugen Sie semantisches HTML gegenüber ARIA, wann immer ein natives Element passt.
- Beschriften Sie jede Eingabe mit einem echten
<label>oderaria-label. - Machen Sie alles per Tastatur bedienbar; die Maus ist optional.
- Automatisieren Sie mit axe-core in jedem Komponententest.
- Testen Sie manuell mit mindestens einem Screenreader.
- Behalten Sie 4.5:1 Kontrast bei normalem Text und sichtbare Fokusindikatoren bei.
- Führen Sie a11y-Prüfungen in CI aus, damit Regressionen nie ausgeliefert werden.
Durch die Kombination von WCAG-Wissen mit dem KI-gestützten Auditing und der Codegenerierung von Cursor können Sie inklusive Schnittstellen erstellen, die für jeden funktionieren. Lassen Sie Cursor die zugängliche Auszeichnung und Tests erstellen, und überprüfen Sie dann die Ergebnisse mit echten Screenreadern, bevor Sie ausliefern.