Fähigkeit zur Prüfung der Barrierefreiheit von Markdown
Von Wikiprompt, der freien Prompt-Enzyklopädie
Fähigkeit zur Prüfung der Barrierefreiheit von Markdown Eine vollständige Fähigkeitsdefinition für einen KI-Agenten, der Markdown-Dokumente auf Barrierefreiheit überprüft, Alt-Texte schreibt und eine Korrekturliste oder eine korrigierte Datei zurückgibt. Enthält Workflow, Referenzleitfäden, Vorlagen, eine Beispielüberprüfung und ein Python-Prüfskript.
Prompt-InhaltSpeichern
🌐
---
name: markdown-accessibility-checker
description: Überprüft Markdown-Dokumentationen (READMEs, Doku-Sites, Wikis, Blogbeiträge, Changelogs) auf Barrierefreiheit - fehlende oder schlechte Bild-Alt-Texte, Überschriftenstruktur, vage oder doppelte Linktexte, nackte URLs, leere Tabellenköpfe, reine Farbanweisungen, GROSSSCHREIBUNG und Emoji-Aufzählungszeichen - und schreibt dann gute Alt-Texte für jedes Bild aus dem Kontext und gibt eine Korrekturliste oder eine korrigierte Datei zurück. Verwenden Sie dies, wenn ein Benutzer darum bittet, "mein README auf Barrierefreiheit zu prüfen", "Alt-Texte für diese Bilder zu schreiben", "unsere Doku Screenreader-freundlich zu machen", oder eine Barrierefreiheitsprüfung für Markdown in CI wünscht.
---
# Markdown-Barrierefreiheitsprüfer
Sie machen Markdown-Dokumente für alle nutzbar, einschließlich Menschen, die Screenreader, Tastaturnavigation, Vergrößerung oder Lesehilfen verwenden. Sie finden die Probleme, die ein Skript erkennen kann, und erledigen dann den Teil, den ein Skript nicht kann: aussagekräftige Alt-Texte und Linktexte schreiben, die zum Zweck des Dokuments passen.
## Dateien in dieser Fertigkeit
- `scripts/check_md_a11y.py` - scannt Markdown-Dateien oder -Ordner und meldet Probleme mit Zeilennummern und Schweregraden (nur Python-3-Standardbibliothek)
- `references/alt-text-guide.md` - wie man Alt-Texte nach Bildtyp schreibt (Screenshots, Diagramme, Schaubilder, Fotos, Logos, Abzeichen, dekorative Bilder)
- `references/structure-and-links.md` - Überschriften, Linktexte, Tabellen, Listen, Hervorhebungen und was jede Regel im Skript bedeutet
- `templates/a11y-review.md` - der Prüfbericht und das Alt-Text-Arbeitsblatt
- `examples/example-readme-review.md` - eine ausgearbeitete Prüfung eines Projekt-READMEs
## Arbeitsablauf
### 1. Umfang der Prüfung festlegen
Fragen Sie, welche Dateien oder Ordner geprüft werden sollen, wer sie liest (Entwickler, Endbenutzer, Studenten) und ob der Benutzer einen Bericht, eine korrigierte Datei oder beides möchte. Wenn die Dokumente von einem Site-Generator gerendert werden, fragen Sie, ob dieser einen eigenen Seitentitel hinzufügt (dann benötigt das Markdown möglicherweise kein H1).
### 2. Prüfer ausführen
```bash
python3 scripts/check_md_a11y.py README.md docs/
python3 scripts/check_md_a11y.py docs/ --json
python3 scripts/check_md_a11y.py docs/ --fail-on warn # für CI
```
Es ignoriert Codeblöcke und Inline-Code. HIGH bedeutet, dass Inhalt für einige Leser verloren geht (fehlender Alt-Text, leerer Link, leere Überschrift), WARN sollte behoben werden, INFO benötigt eine menschliche Prüfung. Wenn Sie das Skript nicht ausführen können, prüfen Sie dieselben Regeln durch Lesen der Datei und sagen Sie dies.
### 3. Alt-Texte schreiben
Bestimmen Sie für jedes markierte Bild und für jedes Bild mit vorhandenem Alt-Text dessen Zweck mithilfe von `references/alt-text-guide.md`:
- Lesen Sie den Text darum herum: Wofür ist das Bild an dieser Stelle im Dokument?
- Wenn Sie das Bild sehen können, beschreiben Sie, was für diesen Zweck wichtig ist. Wenn nicht, fragen Sie den Benutzer oder schreiben Sie einen klar gekennzeichneten Entwurf aus Dateiname und Kontext (z. B. "ENTWURF: gegen das Bild prüfen").
- Dekorative Bilder erhalten leeren Alt-Text; in Markdown bevorzugen Sie das Entfernen oder verwenden Sie HTML `<img alt="">`.
Füllen Sie das Alt-Text-Arbeitsblatt in `templates/a11y-review.md` aus.
### 4. Struktur und Links korrigieren
Wenden Sie `references/structure-and-links.md` an: ein H1, keine übersprungenen Ebenen, echte Überschriften statt fetter Zeilen, beschreibende eindeutige Linktexte, Tabellen mit Kopfzeilen, Anweisungen, die nicht nur auf Farbe beruhen.
### 5. Liefern
- Bericht: Füllen Sie `templates/a11y-review.md` aus, wie in `examples/example-readme-review.md`, mit den wichtigsten Korrekturen zuerst.
- Korrigierte Datei: Geben Sie das vollständige Markdown mit angewendeten Korrekturen und einer kurzen Änderungsliste zurück. Ändern Sie nicht die Bedeutung, Codebeispiele oder Linkziele.
- Führen Sie den Prüfer erneut auf der korrigierten Datei aus und fügen Sie die Vorher- und Nachher-Zählungen hinzu.
## Regeln
- Erfinden Sie niemals, was ein Bild zeigt. Wenn Sie es nicht gesehen haben, markieren Sie den Alt-Text als Entwurf.
- Halten Sie Alt-Texte kurz (normalerweise unter 150 Zeichen); geben Sie lange Erklärungen (Schaubilder, Diagramme) in den Text oder eine Bildunterschrift und sagen Sie dies im Alt-Text.
- Beginnen Sie Alt-Texte nicht mit "Bild von" oder "Foto von".
- Denken Sie daran, dass automatisierte Prüfungen nur einen Teil der Probleme finden; erwähnen Sie immer, was noch manuell geprüft werden muss (Farbkontrast in Bildern, Lesereihenfolge, Videountertitel).
- Respektieren Sie die Stimme des Autors; korrigieren Sie Barrierefreiheit, nicht Stil.
FILE:references/alt-text-guide.md
# Alt-Text-Leitfaden
Alt-Text ersetzt das Bild für Menschen, die es nicht sehen können. Fragen Sie: "Wenn ich dieses Dokument laut vorlese, was würde ich an dieser Stelle sagen, anstatt das Bild zu zeigen?" Die Antwort hängt davon ab, warum das Bild da ist, nicht nur davon, was darauf zu sehen ist.
## Grundlagen
- Seien Sie spezifisch und kurz: normalerweise 5 bis 20 Wörter, selten mehr als 150 Zeichen.
- Beginnen Sie mit dem wichtigen Teil. Beginnen Sie nicht mit "Bild von", "Foto von" oder "Screenshot von", es sei denn, der Typ selbst ist wichtig ("Screenshot" kann helfen, wenn der Leser denselben Bildschirm finden muss).
- Beenden Sie mit einem Punkt, damit Screenreader eine Pause machen.
- Wiederholen Sie nicht die Bildunterschrift oder den Satz neben dem Bild Wort für Wort.
- Fügen Sie Text ein, der im Bild erscheint, wenn der Leser ihn benötigt (Schaltflächenbeschriftungen, Fehlermeldungen).
## Nach Bildtyp
### Screenshots einer App oder Website
Nennen Sie den Bildschirm und die eine Sache, die der Leser beachten sollte.
- Schwach: "Screenshot"
- Besser: "Einstellungsbildschirm mit dem Einheiten-Umschalter auf Metrisch."
### Hero-Bilder und Banner
Wenn es nur die Stimmung setzt, ist es dekorativ. Wenn es das Produkt zeigt, beschreiben Sie es in einem Satz.
- "Trailhead Weather auf einem Telefon, das eine Dreitagesvorhersage für einen Gebirgspass zeigt."
### Diagramme und Flussdiagramme
Geben Sie die Hauptidee im Alt-Text und die vollständige Struktur im Text oder einer Liste direkt nach dem Bild an.
- Alt-Text: "Architekturdiagramm: Die mobile App ruft die API auf, die aus einem Vorhersage-Cache und einem Wetteranbieter liest. Details in der Liste unten."
### Schaubilder und Graphen
Geben Sie den Typ, das Thema und die wichtigste Erkenntnis an; fügen Sie die Daten in einer Tabelle hinzu, wenn Leser Zahlen benötigen.
- "Liniendiagramm der täglich aktiven Benutzer, Januar bis Juni 2026, Anstieg von 2.000 auf 9.500 mit einem Rückgang im April."
### Fotos
Beschreiben Sie, was für den Zweck des Dokuments wichtig ist: Motiv, Aktion, Umgebung.
- "Schneebedeckter Kammweg mit orangefarbenen Markierungsstangen, die zu einer Hütte führen."
### Logos
Verwenden Sie den Organisations- oder Produktnamen plus "Logo" nur, wenn es hilft: "Trailhead Weather Logo."
Wenn das Logo ein Link ist, beschreiben Sie das Ziel: "Trailhead Weather Startseite."
### Abzeichen (Build-Status, Version, Lizenz)
Schreiben Sie die Information, die das Abzeichen zeigt: "Build: erfolgreich", "Lizenz: MIT", "Version 2.4.1".
### Symbole in Text oder Links
Wenn das Symbol eine Funktion hat, beschreiben Sie die Funktion ("Herunterladen"); wenn es nahen Text wiederholt, ist es dekorativ.
### Animierte GIFs und kurze Videos
Beschreiben Sie, was passiert: "Animation: Das Ziehen einer Stecknadel auf die Karte fügt der Liste einen neuen Trailhead hinzu." Videos benötigen auch Untertitel und, für wichtige Inhalte, eine Textalternative.
### Dekorative Bilder
Trennlinien, Hintergrundtexturen und rein visuelle Verzierungen. Verwenden Sie in HTML `alt=""`, damit Screenreader sie überspringen. In Markdown ist `` mehrdeutig (oft ein Fehler), daher bevorzugen Sie das Entfernen des Bildes oder die Verwendung von `<img src="divider.png" alt="">`.
## Häufige Fehler
- Dateinamen als Alt-Text: "IMG_2041.jpg", "hero-final-v3".
- Ein Wort: "Bild", "Logo", "Diagramm".
- Keyword-Stuffing für Suchmaschinen.
- Unterschiedliche Alt-Texte für dasselbe Bild an mehreren Stellen.
- Beschreiben von Farben oder Layout, wenn der Leser die Information benötigt, nicht das Aussehen.
FILE:references/structure-and-links.md
# Struktur, Links und was jede Regel bedeutet
Screenreader-Benutzer springen oft durch ein Dokument über Überschriften oder Links. Gute Struktur macht das möglich.
## Überschriften
| Regel | Schweregrad | Warum | Korrektur |
|---|---|---|---|
| leere-überschrift | HIGH | Eine leere Überschrift wird als "Überschrift Ebene 2" angesagt, ohne dass etwas folgt. | Text hinzufügen oder das # entfernen. |
| kein-h1 | WARN | Die Seite hat keinen Titel in der Überschriftenstruktur. | Beginnen Sie mit einer `# Titel`. Überspringen Sie dies, wenn der Site-Generator das H1 aus den Front-Matter-Daten hinzufügt. |
| mehrere-h1 | WARN | Mehrere Titel verwirren die Struktur. | Behalten Sie ein H1; verwenden Sie `##` für Abschnitte. |
| überschrift-übersprungen | WARN | Ein Sprung von H2 zu H4 deutet auf einen fehlenden Abschnitt hin. | Verwenden Sie die nächste Ebene (H3). Wählen Sie Ebenen für die Struktur, nicht für die Schriftgröße. |
| falsche-überschrift | INFO | Eine fette Zeile sieht wie eine Überschrift aus, ist aber nicht in der Struktur. | Verwenden Sie eine echte Überschrift, wenn ein Abschnitt beginnt; behalten Sie Fettdruck, wenn es nur Hervorhebung ist. |
| keine-überschriften | INFO | Langer Text ohne Überschriften ist schwer zu überfliegen. | Fügen Sie alle paar Absätze Abschnittsüberschriften hinzu. |
## Links
| Regel | Schweregrad | Warum | Korrektur |
|---|---|---|---|
| leerer-link | HIGH | Der Link hat keinen zugänglichen Namen. | Fügen Sie beschreibenden Text hinzu. |
| vager-link | WARN | "Hier klicken" oder "Mehr lesen" bedeutet nichts in einer Liste von Links. | Benennen Sie das Ziel: "die neueste Version herunterladen", "Einrichtungsanleitung". |
| gleicher-text-andere-url | WARN | Zwei Links namens "Doku", die zu verschiedenen Orten führen, sind nicht unterscheidbar. | Machen Sie jeden Text eindeutig: "API-Referenz", "Einrichtungsanleitung". |
| url-als-linktext | INFO | Lange URLs werden Zeichen für Zeichen vorgelesen. | Verwenden Sie eine kurze Beschreibung; behalten Sie die URL nur, wenn Leser sie kopieren müssen. |
| nackte-url | INFO | Wie oben und nicht immer klickbar. | In einen beschreibenden Link einbetten. |
Tipps für Linktexte: Setzen Sie die wichtigen Wörter an den Anfang, halten Sie es kurz, sagen Sie, wenn ein Link eine Datei öffnet ("Preisliste (PDF, 2 MB)"), und verwenden Sie nicht "Link" im Text.
## Bilder
| Regel | Schweregrad | Warum |
|---|---|---|
| bild-ohne-alt | HIGH | `` bietet keine Alternative; einige Screenreader sagen den Dateinamen an. |
| img-ohne-alt | HIGH | `<img>` ohne alt-Attribut; Screenreader fallen auf den Dateinamen zurück. |
| img-allgemeiner-alt | WARN | "Bild", "Screenshot", "Logo" allein tragen keine Information. |
| img-dateiname-alt | WARN | "IMG_2041.jpg" ist keine Beschreibung. |
| img-langer-alt | WARN | Sehr langer Alt-Text kann nicht navigiert werden; verschieben Sie Details in den Text. |
| img-redundanter-alt | INFO | "Bild von" ist redundant; Screenreader sagen bereits "Bild". |
| img-dekorativ | INFO | `alt=""` verbirgt das Bild; bestätigen Sie, dass es wirklich dekorativ ist. |
Siehe `alt-text-guide.md` für das Schreiben des Textes.
## Tabellen
- tabelle-leerer-kopf (WARN): Jede Spalte benötigt eine Kopfzeile, damit Screenreader "Pro, Vorhersagetage, 10" ansagen können. Fügen Sie eine Kopfzeile wie "Funktion" zur ersten Spalte hinzu.
- Verwenden Sie Tabellen für Daten, nicht für Layout. Halten Sie sie klein; teilen Sie sehr breite Tabellen auf.
## Andere Regeln
- nur-farbe (WARN): "Drücken Sie den grünen Knopf" scheitert bei Farbfehlsichtigen und Screenreader-Benutzern. Benennen Sie den Knopf: "Speichern auswählen (der grüne Knopf)".
- grossschreibung (INFO): Langer GROSSGESCHRIEBENER Text ist schwerer zu lesen, und einige Screenreader buchstabieren kurze Großbuchstabenwörter. Verwenden Sie normale Groß-/Kleinschreibung und Fettdruck für Hervorhebung.
- emoji-aufzählung (INFO): Emojis werden mit Namen vorgelesen ("weißes Häkchen Stündliche Vorhersagen"). Verwenden Sie normale Listenmarkierungen und halten Sie Emojis selten und bedeutungsvoll.
## Nicht vom Skript geprüft (manuell prüfen)
- Ob Alt-Texte korrekt und nützlich sind.
- Farbkontrast und Text in Bildern (Screenshots mit winzigem Text, Diagramme mit geringem Kontrast).
- Lesereihenfolge komplexer Layouts und in Markdown eingebetteter HTML-Blöcke.
- Untertitel und Transkripte für Videos und Audio.
- Einfache Sprache: kurze Sätze, definierter Jargon und beschreibende Abschnittsnamen.
FILE:templates/a11y-review.md
# Barrierefreiheitsprüfung: <Dokument oder Ordner>
Datum: <JJJJ-MM-TT>
Geprüfte Dateien: <n> (<Liste oder Ordner>)
Zielgruppe: <wer diese Doku liest>
Prüferlauf: `python3 scripts/check_md_a11y.py <Pfade>` -> HIGH <n>, WARN <n>, INFO <n>
## Wichtigste Korrekturen (größte Wirkung zuerst)
1. <Korrektur> (<Datei:Zeile>)
2. <Korrektur>
3. <Korrektur>
## Alt-Text-Arbeitsblatt
| Datei:Zeile | Bild | Zweck im Dokument | Aktueller Alt-Text | Neuer Alt-Text | Bild gesehen? |
|---|---|---|---|---|---|
| | | informativ / funktional / dekorativ / komplex | | | ja / Entwurf |
## Überschriften
- Aktuelle Struktur: <H1 ... / H2 ... / H4 ...>
- Vorgeschlagene Struktur: <H1 ... / H2 ... / H3 ...>
## Links
| Datei:Zeile | Aktueller Text | Neuer Text | Ziel |
|---|---|---|---|
| | | | |
## Weitere Befunde
| Datei:Zeile | Regel | Änderung |
|---|---|---|
| | | |
## Nach den Korrekturen
Prüferlauf erneut: HIGH <n>, WARN <n>, INFO <n> (verbleibende INFO-Punkte unten erklärt).
- <INFO-Punkt: Grund, warum er akzeptabel ist>
## Noch benötigte manuelle Prüfungen
- <zum Beispiel: Kontrast von Text in Screenshots, Videountertitel>
FILE:examples/example-readme-review.md
# Beispiel: Barrierefreiheitsprüfung eines Projekt-READMEs
## Die Anfrage
"Das README unserer Open-Source-App hat viel Verkehr. Ein Benutzer, der auf einen Screenreader angewiesen ist, sagte, es sei schwer zu folgen. Können Sie es prüfen und korrigieren? Das Hero-Bild ist die App auf einem Telefon mit der 3-Tage-Vorhersage; app-main.png ist der Hauptbildschirm mit stündlicher Temperatur, Wind und Schneegrenze; das Abzeichen ist unser Build-Status."
## Prüferlauf (vorher)
```
$ python3 scripts/check_md_a11y.py README.md
Markdown-Barrierefreiheitsprüfung: 1 Datei(en), 3 Bild(er)
HIGH 2 WARN 8 INFO 5
README.md (3 Bilder, 4 Überschriften): 15 Befund(e)
3 HIGH img-missing-alt Bild hero.png hat leeren Alt-Text; beschreiben Sie es oder bestätigen Sie, dass es rein dekorativ ist.
5 INFO all-caps Langer GROSSGESCHRIEBENER Text ist schwer zu lesen und einige Screenreader buchstabieren ihn Buchstabe für Buchstabe.
9 WARN vague-link Linktext "hier" sagt nicht, wohin er führt; beschreiben Sie das Ziel.
9 WARN vague-link Linktext "hier klicken" sagt nicht, wohin er führt; beschreiben Sie das Ziel.
11 WARN img-generic-alt Alt-Text "Screenshot" für app-main.png ist allgemein; sagen Sie, was das Bild zeigt oder warum es da ist.
13 HIGH img-no-alt <img src="docs/img/badge.svg"> hat kein alt-Attribut.
15 WARN heading-skip Überschriftenebene springt von H2 zu H4 ("Konfiguration"); verwenden Sie H3.
17 WARN color-only Anweisung beruht auf Farbe; fügen Sie auch die Beschriftung, Form oder Position hinzu.
19 INFO fake-heading Fette Zeile "Funktionen" sieht wie eine Überschrift aus; verwenden Sie eine echte #-Überschrift, wenn ein Abschnitt beginnt.
21 INFO emoji-bullet Emoji als Aufzählungszeichen wird mit Namen vorgelesen; verwenden Sie eine Listenmarkierung und geben Sie die Bedeutung in Worten an.
22 INFO emoji-bullet Emoji als Aufzählungszeichen wird mit Namen vorgelesen; verwenden Sie eine Listenmarkierung und geben Sie die Bedeutung in Worten an.
24 WARN table-empty-header Tabellenkopf hat 1 leere Zelle(n); jede Spalte benötigt eine Kopfzeile.
28 WARN same-text-different-url Linktext "Doku" zeigt auf 2 verschiedene URLs; machen Sie jeden Text eindeutig.
28 INFO bare-url Nackte URL https://example.org/docs; Screenreader buchstabieren sie. Verwenden Sie [beschreibender Text](https://example.org/docs).
35 WARN multiple-h1 2 H1-Überschriften (Zeilen 1, 35); behalten Sie einen Titel und verwenden Sie ## für Abschnitte.
```
Das `` im Bash-Codeblock und das Inline-Codebeispiel in der letzten Zeile wurden korrekt ignoriert.
## Die Prüfung (ausgefüllte Vorlage, gekürzt)
# Barrierefreiheitsprüfung: README.md
Zielgruppe: Wanderer und Mitwirkende, viele kommen über die Suche.
Prüferlauf: HIGH 2, WARN 8, INFO 5.
### Wichtigste Korrekturen
1. Geben Sie dem Hero-Bild und dem Build-Abzeichen echten Alt-Text (Zeilen 3 und 13).
2. Ersetzen Sie "hier" und "hier klicken" durch Linktexte, die das Ziel benennen (Zeile 9).
3. Korrigieren Sie die Struktur: "Konfiguration" wird H3, "Funktionen" wird ein echtes H3, und das zweite H1 "Mitwirken" wird H2.
4. Benennen Sie die Speichern-Schaltfläche statt nur ihrer Farbe (Zeile 17).
5. Geben Sie der ersten Tabellenspalte eine Kopfzeile (Zeile 24).
### Alt-Text-Arbeitsblatt
| Datei:Zeile | Bild | Zweck | Aktueller Alt-Text | Neuer Alt-Text | Gesehen? |
|---|---|---|---|---|---|
| README.md:3 | hero.png | informativ: zeigt das Produkt | (leer) | Trailhead Weather auf einem Telefon, das eine Dreitagesvorhersage für einen Gebirgspass zeigt. | vom Benutzer beschrieben |
| README.md:11 | app-main.png | informativ: was der Hauptbildschirm zeigt | Screenshot | Hauptbildschirm mit stündlicher Temperatur, Wind und Schneegrenze für den ausgewählten Trailhead. | vom Benutzer beschrieben |
| README.md:13 | badge.svg | informativ: Build-Status | (kein alt) | Build: erfolgreich | vom Benutzer beschrieben |
### Überschriften
- Vorher: H1 Trailhead Weather / H2 Installieren / H4 Konfiguration / H1 Mitwirken (plus eine fette "Funktionen"-Zeile).
- Nachher: H1 Trailhead Weather / H2 Installieren / H3 Konfiguration / H3 Funktionen / H2 Mitwirken.
### Links
| Zeile | Aktueller Text | Neuer Text | Ziel |
|---|---|---|---|
| 9 | hier | Laden Sie die neueste Version herunter | https://example.org/releases |
| 9 | hier klicken | Einrichtungsanleitung | docs/guides/setup.md |
| 28 | Doku (nackte URL + "Doku") | API-Referenz | https://example.org/docs |
| 28 | Doku | Einrichtungsanleitung | docs/guides/setup.md |
### Weitere Befunde
| Zeile | Regel | Änderung |
|---|---|---|
| 5 | all-caps | Normale Groß-/Kleinschreibung in der fetten Notiz. |
| 17 | color-only | "Speichern auswählen (der grüne Knopf unten in den Einstellungen)". |
| 21-22 | emoji-bullet | Normale "-" Listenelemente. |
| 24 | table-empty-header | Kopfzeile der ersten Spalte "Funktion". |
### Korrigiertes README (Auszug)
```markdown
# Trailhead Weather

Trailhead Weather zeigt Bergvorhersagen für Wanderer. **Hinweis: Dieses Projekt befindet sich noch in der Beta-Phase und Dinge werden oft kaputtgehen.**
## Installieren
[Laden Sie die neueste Version herunter](https://example.org/releases), oder folgen Sie der [Einrichtungsanleitung](docs/guides/setup.md).
<img src="docs/img/badge.svg" width="90" alt="Build: erfolgreich">
### Konfiguration
Wählen Sie Speichern (der grüne Knopf unten in den Einstellungen), um Ihre Einstellungen zu speichern.
### Funktionen
- Stündliche Vorhersagen
- Lawinenbulletins
| Funktion | Kostenlos | Pro |
|---|---|---|
| Vorhersagetage | 3 | 10 |
```
### Nach den Korrekturen
```
$ python3 scripts/check_md_a11y.py README-fixed.md
Markdown-Barrierefreiheitsprüfung: 1 Datei(en), 3 Bild(er)
HIGH 0 WARN 0 INFO 0
```
### Noch benötigte manuelle Prüfungen
- Das Hero-Bild hat kleinen Text auf dem Telefonbildschirm; der Alt-Text trägt die Kernbotschaft, das ist hier in Ordnung.
- Wenn das README jemals in eine Doku-Site-Seite umgewandelt wird, bestätigen Sie, dass die Site kein zweites H1 hinzufügt.
## Warum dies eine gute Antwort ist
- Alt-Text beschreibt den Zweck jedes Bildes und verwendet, was der Benutzer über die Bilder gesagt hat, anstatt zu raten.
- Links und Überschriften werden für die Navigation von Screenreader-Benutzern korrigiert: über Linklisten und Überschriftenstruktur.
- Die Korrektur wird durch erneutes Ausführen des Prüfers verifiziert, und die verbleibenden manuellen Prüfungen werden ehrlich aufgelistet.
FILE:scripts/check_md_a11y.py
#!/usr/bin/env python3
"""Prüft Markdown-Dateien auf häufige Barrierefreiheitsprobleme.
Verwendung:
python3 check_md_a11y.py README.md docs/ # Dateien und Ordner (*.md, *.markdown)
python3 check_md_a11y.py docs/ --json
cat page.md | python3 check_md_a11y.py -
python3 check_md_a11y.py docs/ --fail-on warn # Exit 1 auch bei WARN (für CI)
Prüfungen (Codeblöcke und Inline-Code werden ignoriert):
Bilder fehlender Alt-Text, Dateiname oder allgemeiner Alt-Text ("Bild", "Screenshot"),
redundante "Bild von ..."-Anfänge, sehr langer Alt-Text, HTML <img> ohne alt,
leerer Alt-Text (nur für dekorative Bilder in Ordnung)
Überschriften kein H1 oder mehr als ein H1, übersprungene Ebenen (H2 -> H4), leere Überschriften,
fette Zeilen als falsche Überschriften
Links leerer Linktext, vager Text ("hier klicken", "mehr lesen", "hier"),
nackte URLs, derselbe Text, der auf verschiedene URLs zeigt
Tabellen leere Kopfzellen
Anderes GROSSGESCHRIEBENE Sätze, Emoji als Aufzählungszeichen, reine Farbanweisungen
Schweregrade: HIGH (blockiert Verständnis), WARN (sollte korrigiert werden), INFO (manuell prüfen).
Exit-Code: 0 kein HIGH, 1 HIGH gefunden (oder WARN mit --fail-on warn), 2 Verwendungsfehler.
Nur Standardbibliothek.
"""
import argparse
import json
import os
import re
import sys
GENERIC_ALT = {"bild", "img", "foto", "pic", "photo", "screenshot", "screen shot", "grafik", "symbol",
"logo", "diagramm", "diagram", "chart", "abbildung", "figur", "ohne titel", "alt", "alt text", "banner", "platzhalter"}
VAGUE_LINK = {"hier klicken", "hier", "klicken", "mehr lesen", "mehr", "erfahren sie mehr", "link", "dies", "dieser link",
"diese seite", "los", "details", "mehr info", "info", "siehe hier", "schau es dir an"}
REDUNDANT_START = re.compile(r"^(ein|eine|einer|einem)?\s?(bild|foto|photo|screenshot|grafik) (von|zeigt)\b", re.I)
FILE_ALT = re.compile(r"^[\w\-. ]+\.(png|jpe?g|gif|svg|webp|bmp|tiff?)$|^(img|image|dsc|screenshot)[_\- ]?\d+", re.I)
IMG_MD = re.compile(r"!\[([^\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+\"[^\"]*\")?\s*\)")
IMG_REF = re.compile(r"!\[([^\]]*)\]\[[^\]]*\]")
LINK_MD = re.compile(r"(?<!!)\[([^\]]*)\]\(\s*<?([^)\s>]*)>?(?:\s+\"[^\"]*\")?\s*\)")
HTML_IMG = re.compile(r"<img\b[^>]*>", re.I)
BARE_URL = re.compile(r"(?<![(<\"'=\[])\bhttps?://[^\s)>\]]+")
COLOR_ONLY = re.compile(r"\b(klicken|drücken|tippen|wählen|auswählen|verwenden)\b[^.]{0,30}\b(rot|grün|blau|gelb|orange|lila)\b(?! *\()", re.I)
EMOJI_BULLET = re.compile(r"^\s*[\u2705\u274c\u2b50\u27a1\u2714\u2716\U0001F300-\U0001FAFF]\ufe0f?\s+\S")
def strip_inline_code(line):
return re.sub(r"`+[^`]*`+", lambda m: " " * len(m.group(0)), line)
def check_text(text, name):
findings = []
def add(sev, line, rule, msg):
findings.append({"file": name, "line": line, "severity": sev, "rule": rule, "message": msg})
lines = text.replace("\r\n", "\n").split("\n")
in_fence, fence = False, ""
headings, link_targets = [], {}
images = 0
prev_blank = True
for no, raw in enumerate(lines, 1):
stripped = raw.strip()
m = re.match(r"^\s{0,3}(`{3,}|~{3,})", raw)
if m:
if not in_fence:
in_fence, fence = True, m.group(1)[0] * 3
elif stripped.startswith(fence):
in_fence = False
continue
if in_fence or raw.startswith(" ") and prev_blank and not stripped.startswith(("-", "*", "+")):
prev_blank = not stripped if not in_fence else prev_blank
continue
line = strip_inline_code(raw)
hm = re.match(r"^\s{0,3}(#{1,6})(\s+|$)(.*?)\s*#*\s*$", line)
if hm:
level, title = len(hm.group(1)), hm.group(3).strip()
headings.append((no, level, title))
if not title:
add("HIGH", no, "empty-heading", f"Leere H{level}-Überschrift; Screenreader-Benutzer navigieren über Überschriften.")
elif re.fullmatch(r"\s*(\*\*|__)[^*_]{2,80}(\*\*|__):?\s*", line) and prev_blank:
add("INFO", no, "fake-heading", f"Fette Zeile \"{stripped.strip('*_:')}\" sieht wie eine Überschrift aus; verwenden Sie eine echte #-Überschrift, wenn ein Abschnitt beginnt.")
images += len(IMG_MD.findall(line)) + len(IMG_REF.findall(line)) + len(HTML_IMG.findall(line))
for alt, src in IMG_MD.findall(line):
check_alt(add, no, alt, src)
for alt in IMG_REF.findall(line):
check_alt(add, no, alt, "(referenz)")
for tag in HTML_IMG.findall(line):
am = re.search(r"\balt\s*=\s*(\"([^\"]*)\"|'([^']*)'|(\S+))", tag, re.I)
src = re.search(r"\bsrc\s*=\s*[\"']?([^\"'\s>]+)", tag, re.I)
src = src.group(1) if src else "?"
if not am:
add("HIGH", no, "img-no-alt", f"<img src=\"{src}\"> hat kein alt-Attribut.")
else:
check_alt(add, no, am.group(2) if am.group(2) is not None else (am.group(3) if am.group(3) is not None else am.group(4)), src, html=True)
no_images = IMG_MD.sub(" ", line)
for text_, url in LINK_MD.findall(no_images):
label = re.sub(r"[*_`]", "", text_).strip()
if not label:
add("HIGH", no, "empty-link", f"Link zu {url or '(keine URL)'} hat keinen Text; Screenreader lesen die URL oder nichts vor.")
elif label.lower().rstrip(".!:") in VAGUE_LINK:
add("WARN", no, "vague-link", f"Linktext \"{label}\" sagt nicht, wohin er führt; beschreiben Sie das Ziel.")
elif re.fullmatch(r"https?://\S+", label):
add("INFO", no, "url-as-link-text", f"Linktext ist eine rohe URL ({label[:60]}); verwenden Sie eine kurze Beschreibung.")
if label:
link_targets.setdefault(label.lower(), {}).setdefault(url, no)
for url in BARE_URL.findall(LINK_MD.sub(" ", no_images)):
add("INFO", no, "bare-url", f"Nackte URL {url[:60]}; Screenreader buchstabieren sie. Verwenden Sie [beschreibender Text]({url[:40]}).")
if "|" in line and re.match(r"^\s*\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$", line) and no > 1:
header = lines[no - 2].strip().strip("|")
cells = [c.strip() for c in header.split("|")]
if any(not c for c in cells):
add("WARN", no - 1, "table-empty-header", f"Tabellenkopf hat {sum(1 for c in cells if not c)} leere Zelle(n); jede Spalte benötigt eine Kopfzeile.")
run = longest = 0
for w in re.findall(r"[A-Za-zÄÖÜäöüß]+", line):
run = run + 1 if w.isupper() and (len(w) > 1 or w in "AI") else 0
longest = max(longest, run)
if longest >= 5 and not hm:
add("INFO", no, "all-caps", "Langer GROSSGESCHRIEBENER Text ist schwer zu lesen und einige Screenreader buchstabieren ihn Buchstabe für Buchstabe.")
if EMOJI_BULLET.match(line):
add("INFO", no, "emoji-bullet", "Emoji als Aufzählungszeichen wird mit Namen vorgelesen; verwenden Sie eine Listenmarkierung und halten Sie Emojis selten und bedeutungsvoll.")
cm = COLOR_ONLY.search(line)
if cm:
between = line[cm.end(1):cm.start(2)]
inside_parens = line[:cm.start(2)].count("(") > line[:cm.start(2)].count(")")
names_label = re.match(r"\s+(\*\*|\"|')?[A-ZÄÖÜ]", between) # "Speichern auswählen ..." oder "Drücken Sie **Speichern**"
if inside_parens or names_label:
cm = None
if cm:
add("WARN", no, "color-only", "Anweisung beruht auf Farbe; fügen Sie auch die Beschriftung, Form oder Position hinzu.")
prev_blank = not stripped
h1 = [h for h in headings if h[1] == 1]
if headings and not h1:
add("WARN", headings[0][0], "no-h1", "Dokument hat kein H1; beginnen Sie mit einer # Titel.")
if len(h1) > 1:
add("WARN", h1[1][0], "multiple-h1", f"{len(h1)} H1-Überschriften (Zeilen {', '.join(str(h[0]) for h in h1)}); behalten Sie einen Titel und verwenden Sie ## für Abschnitte.")
for (pno, plev, _), (no, lev, title) in zip(headings, headings[1:]):
if lev > plev + 1:
add("WARN", no, "heading-skip", f"Überschriftenebene springt von H{plev} zu H{lev} (\"{title[:50]}\"); verwenden Sie H{plev + 1}.")
if not headings and len([l for l in lines if l.strip()]) > 15:
add("INFO", 1, "no-headings", "Langes Dokument ohne Überschriften; fügen Sie Überschriften hinzu, damit Leser navigieren können.")
for label, targets in link_targets.items():
if len(targets) > 1 and label not in VAGUE_LINK:
first = min(targets.values())
add("WARN", first, "same-text-different-url", f"Linktext \"{label}\" zeigt auf {len(targets)} verschiedene URLs; machen Sie jeden Text eindeutig.")
order = {"HIGH": 0, "WARN": 1, "INFO": 2}
findings.sort(key=lambda f: (f["line"], order[f["severity"]]))
return findings, len(headings), images
def check_alt(add, no, alt, src, html=False):
a = alt.strip()
base = os.path.basename(src) if src else ""
if a == "" and html:
add("INFO", no, "img-decorative", f"<img src=\"{base}\"> hat alt=\"\" (als dekorativ markiert); bestätigen Sie, dass es keine Information trägt.")
return
if a == "" and src:
add("HIGH", no, "img-missing-alt", f"Bild {base or src} hat leeren Alt-Text; beschreiben Sie es oder bestätigen Sie, dass es rein dekorativ ist.")
return
low = a.lower().rstrip(".")
if low in GENERIC_ALT:
add("WARN", no, "img-generic-alt", f"Alt-Text \"{a}\" für {base} ist allgemein; sagen Sie, was das Bild zeigt oder warum es da ist.")
elif FILE_ALT.search(a) or (base and low == os.path.splitext(base)[0].lower()):
add("WARN", no, "img-filename-alt", f"Alt-Text \"{a}\" sieht wie ein Dateiname aus; beschreiben Sie das Bild stattdessen.")
elif REDUNDANT_START.match(a):
add("INFO", no, "img-redundant-alt", f"Alt-Text beginnt mit \"{' '.join(a.split()[:3])}\"; Screenreader sagen bereits 'Bild', beginnen Sie also mit dem Inhalt.")
if len(a) > 150:
add("WARN", no, "img-long-alt", f"Alt-Text ist {len(a)} Zeichen; halten Sie ihn unter etwa 150 und verschieben Sie Details in den umgebenden Text oder eine Bildunterschrift.")
def collect(paths):
files = []
for p in paths:
if p == "-":
files.append("-")
elif os.path.isdir(p):
for root, dirs, names in os.walk(p):
dirs[:] = sorted(d for d in dirs if not d.startswith(".") and d != "node_modules")
files += [os.path.join(root, n) for n in sorted(names) if n.lower().endswith((".md", ".markdown"))]
elif os.path.isfile(p):
files.append(p)
else:
raise FileNotFoundError(p)
return files
def main():
ap = argparse.ArgumentParser(description="Markdown-Barrierefreiheitsprüfer")
ap.add_argument("paths", nargs="+", help="Markdown-Dateien, Ordner oder - für stdin")
ap.add_argument("--json", action="store_true")
ap.add_argument("--fail-on", choices=["high", "warn"], default="high")
args = ap.parse_args()
try:
files = collect(args.paths)
except FileNotFoundError as e:
print(f"Fehler: Pfad nicht gefunden: {e}", file=sys.stderr)
return 2
if not files:
print("Fehler: keine Markdown-Dateien (*.md, *.markdown) gefunden", file=sys.stderr)
return 2
all_findings, stats = [], []
for f in files:
text = sys.stdin.read() if f == "-" else open(f, encoding="utf-8", errors="replace").read()
name = "<stdin>" if f == "-" else f
found, nhead, images = check_text(text, name)
stats.append({"file": name, "images": images, "headings": nhead, "findings": len(found)})
all_findings += found
counts = {s: sum(1 for x in all_findings if x["severity"] == s) for s in ("HIGH", "WARN", "INFO")}
if args.json:
print(json.dumps({"files": stats, "counts": counts, "findings": all_findings}, indent=2))
else:
print(f"Markdown-Barrierefreiheitsprüfung: {len(files)} Datei(en), {sum(s['images'] for s in stats)} Bild(er)")
print(f"HIGH {counts['HIGH']} WARN {counts['WARN']} INFO {counts['INFO']}")
for s in stats:
items = [x for x in all_findings if x["file"] == s["file"]]
print(f"\n{s['file']} ({s['images']} Bilder, {s['headings']} Überschriften): {len(items)} Befund(e)")
for x in items:
print(f" {x['line']:>4} {x['severity']:<4} {x['rule']:<24} {x['message']}")
print("\nAutomatisierte Prüfungen decken nur einen Teil der Barrierefreiheit ab; überprüfen Sie Alt-Text-Bedeutung, Lesereihenfolge und Kontrast manuell.")
bad = counts["HIGH"] + (counts["WARN"] if args.fail_on == "warn" else 0)
return 1 if bad else 0
if __name__ == "__main__":
sys.exit(main())
Melde dich an, um den vollständigen Prompt zu sehen
Weiter mit:
Mit der Anmeldung akzeptierst du unsere Nutzungsbedingungen und Datenschutz
Verwendung
Dieser Prompt ist für die Verwendung mit productivity gedacht. Kopiere den Inhalt oben und füge ihn in dein bevorzugtes KI-Tool ein.
Für beste Ergebnisse passe die Platzhalter (eckige Klammern oder Großbuchstaben) an deine Anforderungen an.
Diskussion
0 Kommentare