WCAG-Konformitätszuordnung

Wie sich einzelne Regelergebnisse zu einem WCAG-Erfolgskriterium (SC) verhalten und was surea11y über die Gesamtkonformität aussagen kann und was nicht.

Die drei Ebenen

  1. Atomare Regeln (checksResults[]): jeweils eine normative Entscheidung, z. B. „hat dieses <img> ein alt-Attribut“. Alle finden Sie im Regelkatalog.
  2. Facetten: Ein WCAG-SC ist meist größer als das, was eine einzelne Regel deterministisch entscheiden kann. Intern wird jedes SC in benannte „Facetten“ zerlegt (1.1.1 Nicht-Text-Inhalt hat z. B. Facetten wie img-alt-attr-present, text-alternative-quality, decorative-null), erfasst in src/coverage/wcag-facets.js und jeweils markiert als full (eine Regel entscheidet sie mit hoher Sicherheit), partial (eine Regel entscheidet einen Teil davon; siehe die Hinweise zum Umfang der jeweiligen Regel) oder manual (es gibt überhaupt keine sichere automatische Heuristik). Führen Sie npm run coverage aus, um coverage/coverage-report.md neu zu erzeugen, die Aufschlüsselung der Facetten pro SC.
  3. Zusammengesetzte Regeln (Zusammenfassung pro WCAG-SC) (rulesResults[]): ein generiertes Aggregat aller atomaren Regeln, die einem SC zugeordnet sind. Sie bekommen damit ein Urteil pass/fail/cantTell/notApplicable pro SC, statt Dutzende atomarer Ergebnisse selbst zusammenzufassen. Siehe die vollständige Liste (z. B. fasst wcag-1.1.1-non-text-content 21 atomare Regeln zusammen).

Wie das Ergebnis einer zusammengesetzten Regel berechnet wird

Eine deterministische Rangfolge, ausgewertet über die beitragenden atomaren Regeln dieser zusammengesetzten Regel:

Rangfolge für das Ergebnis zusammengesetzter Regeln
BedingungGesamtergebnis
Mindestens eine beitragende Regel ergibt failfail
Kein fail, aber mindestens eine beitragende Regel ergibt cantTell oder eine aufgeführte beitragende Regel wurde gar nicht ausgeführtcantTell
Alle beitragenden Regeln ergeben notApplicable, bei einem Kriterium, dessen Regeln jeden Fall finden, für den es giltnotApplicable
Alle beitragenden Regeln ergeben notApplicable, bei jedem anderen KriteriumcantTell (composite.rollup.cantTell.partialCoverage)
Andernfalls (alle ausgeführt, keine ergibt fail/cantTell, nicht alle N/A), bei einem Kriterium, dessen Regeln alles prüfen, was es verlangtpass
Andernfalls, bei jedem anderen KriteriumcantTell (composite.rollup.cantTell.partialCheck)

Wann ein Kriterium erfüllt und wann es nicht anwendbar ist

Seit 1.14 gilt ein Kriterium nur dann als erfüllt, wenn seine Regeln alles prüfen, was es verlangt, so wie WCAG es nur dann als erfüllt ansieht, wenn es ganz erfüllt ist. Ergeben alle Regeln pass, heißt das nur, dass die Teile erfüllt sind, die sie prüfen: html-lang-attr-present stellt fest, dass <html lang="fr"> eine Sprache nennt, nicht, dass die Seite auf Französisch ist (3.1.1), und page-title-present, dass die Seite einen Titel hat, nicht, dass er die Seite beschreibt (2.4.2). Ein solches Kriterium ergibt cantTell, mit dem Reason-Code composite.rollup.cantTell.partialCheck, und der HTML-Bericht meldet es als teilweise geprüft („Teilweise geprüft“): Den Rest prüft eine Person. Die Kriterien, die ihre Regeln ganz prüfen, stehen in src/coverage/complete-applicability.js (COMPLETE_CHECK), jeweils mit Begründung, und noch ist es keines: Jedes fragt etwas, das die Regeln nicht sehen, ob eine Textalternative, ein Label, eine Überschrift oder der Text eines Links das Richtige sagt, oder wie Inhalte, die ein Skript zeichnet oder ändert, es erfüllen. In 1.14 ergibt daher keine zusammengesetzte WCAG-Regel pass.

Ebenso ist ein Kriterium nur dann notApplicable, wenn seine Regeln jeden Fall finden, für den es gilt: Links für 2.4.4 und 2.4.9, fokussierbare Elemente für 2.4.3 und 2.4.7, beschriftete Komponenten für 2.5.3, Markup für 4.1.1. Formularfelder (1.3.5, 3.3.2) und Zeigerziele (2.5.8) stehen nicht auf dieser Liste: Ein Feld aus einer ARIA-Rolle, ein Feld ohne autocomplete oder ein Element, das nur durch ein Skript zum Ziel wird, kann auf einer Seite sein, auf der diese Regeln nichts gefunden haben. Bei jedem anderen Kriterium sagen Regeln, die alle nichts gefunden haben, nur, dass die Fälle fehlen, nach denen sie suchen: Ein Skript, das nach einer Verzögerung weiterleitet, ist eine Zeitbegrenzung (2.2.1) ohne <meta http-equiv="refresh">, und eine Passage in einer anderen Sprache (3.1.2) muss kein lang tragen. In den Begriffen von WCAG-EM setzt „nicht vorhanden“ voraus, dass jede Stelle angesehen wurde, an der der Inhalt sein könnte; ein solches Kriterium ergibt daher cantTell, mit dem Reason-Code composite.rollup.cantTell.partialCoverage.

Das heißt: Ein zusammengesetztes fail ist ein echter, deterministischer Verstoß, und ein zusammengesetztes cantTell, dessen beitragende Regeln alle pass ergeben haben (partialCheck), sagt: Jede automatische Prüfung für dieses Kriterium ist ohne Befund geblieben, und den Rest prüft eine Person. Für sich genommen ist das keine Aussage über Konformität. Die Facettentabelle (coverage-report.md) zeigt, welche Teile jedes Kriteriums automatisch abgedeckt sind und welche eine Person prüft. Zeigen Sie diese als „Prüfungen bestanden, Prüfung durch eine Person nötig“ und „nichts zu prüfen gefunden“, nie als erfüllt.

Das Array data.details.contributors einer zusammengesetzten Regel (siehe das Ausgabeschema) listet jede atomare Regel und ihr einzelnes Ergebnis. Daran sehen Sie genau, welche Facette(n) ein fail/cantTell verursacht haben, statt die zusammengesetzte Regel als Blackbox zu behandeln.

Eine eigene Regel (engineOptions.customRules) oder eine Regel eines Packs, die gelaufen ist, zählt für die zusammengesetzte Regel jedes Kriteriums, dem sie über meta.wcagSc oder einen WCAG-Eintrag in meta.normativeMappings zugeordnet ist, genau wie eine eingebaute Regel: Schlägt sie fehl, schlägt die zusammengesetzte Regel fehl. Die zusammengesetzte Regel kennzeichnet eine eigene Regel unter ihren beitragenden Regeln mit custom: true und listet sie in data.details.customChecksIds, da eigene Regeln nicht wie die eingebauten gegen die Spezifikationen geprüft sind. Eine Überschreibung einer eingebauten Regel zählt dort, wo ihre eigene Zuordnung es sagt: an der Stelle der eingebauten Regel, wenn sie diesem Kriterium zugeordnet ist, und nirgends, wenn sie keinem zugeordnet ist (mit einer Warnung).

Ein Scan, der Regeln statt Kriterien nennt (per ID, etwa includeRuleIds: ['link-name-present'], per Tag, das kein WCAG-Tag ist, per optInRules oder als die Best Practices), bekommt ebenfalls die zusammengesetzten Regeln der Kriterien, die diese Regeln prüfen; ein Kriteriums-Tag wie wcag244 meldet nur dieses Kriterium (siehe Engine-Optionen). Vor 1.12 meldete ein solcher Scan keine. Die Tabelle oben entscheidet über sie: Eine Regel mit fail lässt das Kriterium scheitern, und die Regeln, die der Scan nicht ausgewählt hat, sind Beitragende, die nicht gelaufen sind; das Kriterium ist also bestenfalls cantTell, teilweise geprüft (reasonCode composite.rollup.cantTell.notSelectedChild, jede solche beitragende Regel mit notSelected: true markiert; „Teilweise geprüft“ im HTML-Bericht).

Eine Konformitätsstufe anpeilen (A / AA / AAA)

Nennen Sie WCAG-Version und -Stufe in runOnly.wcag:

// WCAG 2.2 Level A and AA:
runDomRulesInPage(url, null, {}, { wcag: { version: '2.2', level: 'AA' } });
 
// The same, and the best-practice rules, which test no WCAG criterion:
runDomRulesInPage(url, null, {}, { wcag: { version: '2.2', level: 'AA' }, bestPractices: true });

Ein Ziel führt die Regeln für jedes Kriterium aus, das in dieser Version auf dieser Stufe und darunter gilt, nach der Stufe, die jedes Kriterium in dieser Version hat (WCAG_CRITERIA in @surea11y/core/wcag); 4.1.1 Syntaxanalyse gehört also zu Zielen für 2.0 und 2.1, nicht aber zu Zielen für 2.2. Es legt außerdem die WCAG-Version des Laufs und die Stufe der gemeldeten Zusammenfassungen fest. Siehe Auswahl nach WCAG-Ziel.

Jeder Eintrag in WCAG_CRITERIA hat außerdem die id, die das W3C dem Kriterium in WCAG 2.2 gibt (non-text-content). Jede WCAG-Zuordnung einer Regel verlinkt den Abschnitt ihres Kriteriums in der Empfehlung dieser Version (url) und sein Understanding-Dokument (understandingUrl), für 2.1 und 2.2: Die Reporter verwenden das Understanding-Dokument als Hilfelink einer Regel, wenn die Regel keinen eigenen hat.

Mit Tags

Dieselben Ziele lassen sich auch mit Stufen-Tags angeben, in runOnly.tags (oder engineOptions.tags.include):

// WCAG 2.0 A and AA. Both tags are required: they are not cumulative.
runDomRulesInPage(url, null, {}, { tags: ['wcag2a', 'wcag2aa'] });

Stufen-Tags sind nicht verschachtelt, und genau das wird hier am leichtesten falsch gemacht. Eine Regel trägt ein Stufen-Tag pro zugeordnetem Erfolgskriterium, mehr nicht: Eine Regel, die nur einem AA-Kriterium zugeordnet ist, trägt wcag2aa und nicht wcag2a. { tags: ['wcag2aa'] } allein führt daher die 11 Regeln aus, die einem AA-Kriterium von 2.0 zugeordnet sind, nicht die 105, die ein Ziel 2.0 A + AA ausmachen. Listen Sie jede Stufe auf, die Sie meinen, oder verwenden Sie runOnly.wcag, das dieses Problem nicht hat. Auch engineOptions.profile (wcag22-aa, en301549-v4.1.1, en301549-v3.2.1, section508) erledigt das für Sie; siehe Konformitätsprofile.

Dasselbe gilt über WCAG-Versionen hinweg: Ein Kriterium, das in 2.1 oder 2.2 eingeführt wurde, trägt nur sein eigenes Herkunfts-Tag. Ein vollständiges Konformitätsziel ist also eine Vereinigung von Tag-Sätzen. Die fertigen Sätze pro Version, einschließlich des einen Kriteriums, das WCAG 2.2 entfernt statt hinzugefügt hat, finden Sie in der Anleitung zu den Engine-Optionen.

Um das entfernte Kriterium kümmert sich die Engine. Jeder Lauf ermittelt eine Ziel-Version von WCAG (engineOptions.wcagVersion, sonst die wcagVersion des Pack-Profils, das der Lauf anwendet, sonst die Version von runOnly.wcag, sonst was Ihre Versions-Tags nahelegen, sonst 2.2) und meldet sie als engine.wcagVersion zurück. Bei einem 2.2-Ziel kann eine Regel, die nur SC 4.1.1 Syntaxanalyse zugeordnet ist, kein fail melden: Sie läuft, meldet ihre Vorkommen und liefert cantTell mit einem Feld wcagVersionScope, das die Umwandlung erklärt. Seit 1.14 tut sie bei einem Ziel 2.0 oder 2.1 dasselbe, mit wcagVersionScope.by: "errata": Die Errata des W3C von 2023 zu diesen Versionen werten 4.1.1 für Inhalte in HTML oder XML als immer erfüllt. Kein WCAG-Scan scheitert also an 4.1.1; nur ein Profil, dessen Standard den Text beibehält, eines mit keepsParsing: true wie en301549-v3.2.1, lässt es noch fehlschlagen.

Zusammengesetzte Regeln werden, anders als atomare, sehr wohl kumulativ gefiltert. Der Runner liest engineOptions.wcagLevel, sonst die Stufe von runOnly.wcag oder die höchste in tags genannte Stufe, und verwirft jede zusammengesetzte Regel darüber; mit ['wcag2a', 'wcag2aa'] gibt es also keinen rulesResults-Eintrag für ein SC, das nur AAA ist. wcagLevel ('A', 'AA' oder 'AAA') ist die Option für einen Scan, der Prüfungen statt eines Ziels nennt: Jede ausgewählte Regel läuft weiterhin, nur die gemeldeten Kriterien werden auf diese Stufe begrenzt, sodass ein Scan von contrast-computable bei 'AA' 1.4.3 meldet und nicht das AAA-Kriterium 1.4.6. Der Lauf hält sie als engine.wcagLevel fest. Die genaue Rangfolge steht in targetWcagLevelOf/isAllowedByTargetLevel in src/core/dom-runner.js.

Lassen Sie tags ganz weg (der Standard), laufen alle Regeln auf allen Stufen, ohne dass zusammengesetzte Regeln unterdrückt werden.

EN 301 549

Veraltet

EN 301 549 zieht in ein eigenes Pack um, @surea11y/pack-en301549, und entfällt in core 2.0.0, mit seinen Profilen, seinem mappings-Schlüssel und @surea11y/core/en301549. Alles funktioniert wie bisher, mit einem console.warn pro Prozess. Zum Umstieg übergeben Sie das Pack in engineOptions.packs: Der Scan übernimmt dieselben Namen aus dem Pack, und @surea11y/pack-en301549/public hat die Exporte der Tabelle. Siehe wie core eine Norm abkündigt.

Kapitel 9 der EN 301 549 gibt die WCAG-Erfolgskriterien der Stufen A und AA als Klauseln wieder, nummeriert mit 9. plus der Nummer des Kriteriums: WCAG 1.4.3 ist Klausel 9.1.4.3. Wenn ein Scan sie anfordert, trägt jedes atomare und zusammengesetzte Ergebnis nach seinen WCAG-Einträgen in meta.normativeMappings die Klausel jedes seiner Kriterien, einmal pro Version der Norm, die dieses Kriterium enthält. Ein Scan fordert sie mit engineOptions.mappings: ['en301549'] (beide Versionen) oder ['en301549:V3.2.1'] (eine) an oder über ein EN-301-549-Profil, das die genannte Version hinzufügt; standardmäßig nennen Ergebnisse nur WCAG (siehe Andere Normen).

VersionBasiert aufUnterscheidet sich von der anderen durch
V3.2.1 (2021-03)WCAG 2.1 A und AA, 50 KriterienEnthält 9.4.1.1 Syntaxanalyse
V4.1.1 (2026-09)WCAG 2.2 A und AA, 55 KriterienErgänzt 2.4.11, 2.5.7, 2.5.8, 3.2.6, 3.3.7, 3.3.8; 9.4.1.1 entfällt

Jeder Klausel-Eintrag nennt außerdem das Kriterium, das er wiedergibt, als wcagSc: ["1.4.3"], damit eine nach Kriterium gruppierte Ansicht (die Suites im JUnit-Bericht, die Zusammenfassung im HTML-Bericht) ihn auch bei einer Regel mit mehreren Kriterien richtig einordnet. AAA-Kriterien haben in keiner Version eine Klausel. Die Kataloge nennen die Klauseln bei denselben Optionen: getChecksCatalog({ mappings: ['en301549'] }) im normativeMappings jedes Eintrags, und die zusammengesetzten Einträge aus getRulesCatalog({ mappings: ['en301549'] }) als meta.standardMappings, sodass sich die Klauseln eines Kriteriums ohne Scan ablesen lassen.

Die Tabelle ist als @surea11y/core/en301549 öffentlich, für Werkzeuge, die die umgekehrte Sicht brauchen, etwa welche Kriterien eine Version verlangt, die ein Scan nicht abgedeckt hat:

const { EN301549_CLAUSES, en301549ClausesForSc } = require('@surea11y/core/en301549');
 
Object.keys(EN301549_CLAUSES['V3.2.1']); // the 50 WCAG 2.1 A and AA criteria V3.2.1 restates
en301549ClausesForSc('2.5.8'); // [{ version: 'V4.1.1', clause: '9.2.5.8', title: 'Target size (minimum)' }]

Das ist eine Zuordnung zwischen zwei veröffentlichten Dokumenten, keine Konformitätsaussage: Eine Klausel an einem Ergebnis sagt, welche Anforderung der EN 301 549 dieses WCAG-Kriterium ist, nicht mehr. Welche Version ein bestimmtes Gesetz verlangt, liegt außerhalb der Engine.

EN 301 549 ist ein Eintrag in einem Register von Normen, das Runner, Regelkatalog und Berichtsgeneratoren lesen. Eine Norm mit eigenen Urteilen (Anforderungen, die ihre eigenen Regeln prüfen, etwa eine nationale Norm wie RGAA) oder die Checkliste einer Organisation kommt als Pack: ein eigenes Paket außerhalb von core, das ein Scan in engineOptions.packs übernimmt und dessen Eintrag für diesen Scan dem Register beitritt, mit eigenen Profilen, Regeln und Zusammenfassungen. Eine eigene Regel kann in ihren eigenen normativeMappings jede beliebige Norm nennen, aber nur registrierte Normen (die von core und die der Packs des Scans) erhalten ein Profil, einen mappings-Schalter, Opt-in-Regeln, Zusammenfassungen oder einen Platz in SARIF, JUnit und dem HTML-Bericht. Wie eine Norm in core selbst eingebaut wird, steht in WCAG_CONFORMANCE.md, dem Leitfaden für Beitragende auf GitHub.

Was diese Engine nicht aussagen kann

Kein automatisches Tool, auch dieses nicht, kann volle WCAG-Konformität bescheinigen. Das ist keine Einschränkung speziell von surea11y, sondern liegt in WCAG selbst: Ein erheblicher Teil der Erfolgskriterien verlangt menschliches Urteil (ist dieser Alternativtext zutreffend, nicht nur vorhanden; ist diese Fehlermeldung verständlich) oder dynamische Tests, die die Architektur dieser Engine als statischer DOM-Scan gar nicht leisten kann (Erkennung von Tastaturfallen, echtes Layout bzw. Reflow beim Zoomen). Die vollständige, ausdrückliche Liste dessen, was außerhalb des Umfangs liegt und warum, finden Sie unter Bekannte Einschränkungen.

Was surea11y Ihnen ehrlicherweise geben kann:

  • Die eingebauten Regeln von core sind so geschrieben, dass sie nur bei einem deterministischen, normativen Verstoß gegen die angepeilte Norm und Version fail ergeben und cantTell melden, wenn sie nicht sicher sein können. Das ist ein Entwurfsziel, keine Garantie: Die Seite Bekannte Einschränkungen nennt Grenzfälle, in denen eine Regel trotzdem falsch liegen kann, die Vorkommen jedes Befunds zeigen, worauf er beruht, und die Seite Regeln nennt die Konfidenz jeder Regel. Wie genau eine eigene Regel, eine Regel eines Packs oder eine Überschreibung ist, hängt davon ab, wie sie geschrieben wurde. Standardmäßig ist diese Norm WCAG. Eine Regel für eine Anforderung, die nur eine andere Norm stellt, ist eine Opt-in-Regel: Standardmäßig läuft sie nur, wenn Sie diese Norm als Ziel wählen (siehe Opt-in-Regeln). engineOptions.optInRules schaltet Opt-in-Regeln frei, ohne das Profil oder die Filter des Scans zu entfernen. Mit optInRules: 'all' und ohne Profil und Filter umfasst der Lauf jede Regel und zielt auf keine einzelne Norm; eine Liste von Tags schaltet nur diese Gruppen von Opt-in-Regeln frei. engine.optInRules nennt die Tags, deren Regeln gelaufen sind. Unter einem WCAG-Profil läuft eine freigeschaltete Regel nur, wenn ihre Tags zu diesem Profil passen, und der Lauf zielt weiterhin auf WCAG. Unter den Regeln von core führt ein Scan mit WCAG-Ziel also nur die Regeln für die Kriterien des Ziels aus, dazu die Best-Practice-Regeln, wenn Sie sie ergänzen. Eine Best-Practice-Regel nennt kein Kriterium und kann trotzdem fail melden, wo das Gefundene selbst eine Barriere ist, etwa eine leere Überschrift (empty-heading); keine zusammengesetzte WCAG-Regel zählt sie mit. Eine eigene Regel, eine Überschreibung oder eine Regel eines Packs ohne Opt-in-Tag läuft, wenn die Auswahl sie einschließt, und kann dann für eine eigene Prüfung, die WCAG nicht verlangt, fail melden.
  • Jedes cantTell ist eine ausdrückliche Markierung zur menschlichen Prüfung, keine verschluckte Unsicherheit.
  • Eine zusammengesetzte Regel ergibt nie pass für ein Kriterium, das ihre Regeln nur zum Teil prüfen: Ergeben sie alle pass, ist sie cantTell (composite.rollup.cantTell.partialCheck). Ein pass verschweigt also nie einen Teil, den keine Regel prüft.
  • Die Tabelle zur Facettenabdeckung zeigt Ihnen genau, welche Teile welcher SC gar keine automatische Abdeckung haben, und damit, was einer Person bleibt.

Kein zusammengesetztes fail für jedes SC Ihrer Zielstufe bedeutet: Jede automatisierbare Prüfung für diese Stufe ist ohne Befund geblieben. Das ist der automatisierbare Teil der Konformität, präzise benannt, kein Ersatz für die manuelle Prüfung, die WCAG selbst verlangt.