Testen von benutzerdefinierten Elementen, die ElementInternals verwenden
Wie Axe DevTools für Web ARIA-Semantiken von ElementInternals liest, was Ihre Komponenten tun müssen, um sie offenzulegen, und welche Sprachen dies unterstützen.
Web-Komponenten können ihre Zugänglichkeitssemantiken in JavaScript anstatt im Markup deklarieren, indem sie attachInternals() aufrufen und Eigenschaften wie role und ariaLabel auf dem zurückgegebenen ElementInternals-Objekt setzen. Eine so gebaute Komponente hat keine role- oder aria-*-Attribute im DOM, sodass ein Testwerkzeug, das nur Attribute liest, ein Element ohne jegliche Semantik sieht.
Axe DevTools für Web liest nun diese Semantiken. Diese Seite erklärt, welche Versionen dies unterstützen, was Ihre Komponenten tun müssen, um ihre Internas sichtbar zu machen, und wie die Internas mit den bereits am Element vorhandenen Attributen interagieren. Allgemeine Informationen zur Auswahl Ihrer axe-core-Version finden Sie unter Regeln anpassen.
Unterstützte Sprachen und Versionen
Die Unterstützung kommt vom zugrunde liegenden Accessibility-Testing-Engine, sodass sie überall dort verfügbar ist, wo die mitgelieferte axe-core-Version 4.13.0 oder höher ist.
| Sprache | Version, die Unterstützung hinzugefügt hat | Mitgeliefertes axe-core |
|---|---|---|
| C# | 4.13.0 | 4.13.0 |
| Python | 4.13.0 | 4.13.0 |
| Ruby | 4.13.0 | 4.13.0 (über axe-core-api 4.13.0) |
| Java | 4.13.0 | 4.13.0 (über com.deque.html.axe-core 4.13.0) |
| Node.js und die CLI | 4.13.0 | 4.13.0 |
Es gibt nichts einzuschalten. In jeder oben genannten Sprache läuft die Accessibility-Testing-Engine direkt auf der zu testenden Seite, sodass sie bei jedem Scan ElementInternals liest, ohne dass eine Option, ein Flag oder eine Konfigurationsänderung erforderlich ist. Wenn Ihre Komponenten bereits dem unten beschriebenen Protokoll folgen, ist nur ein Upgrade erforderlich.
Offenlegung von ElementInternals für Axe DevTools
ElementInternals ist aus Designgründen privat: JavaScript bietet keine API zum Lesen der Internas eines anderen Elements. Ein Testwerkzeug kann das Objekt nur sehen, wenn Ihre Komponente es absichtlich veröffentlicht. Komponentenautoren tun dies über ein Community-Protokoll, und Axe DevTools unterstützt jede Form dieses Protokolls.
Die empfohlene Form ist ein globales WeakMap, das das Objekt vom Element selbst fernhält:
customElements.define(
'my-custom-button',
class MyCustomButton extends HTMLElement {
constructor() {
super();
const internals = this.attachInternals();
internals.role = 'button';
globalThis._elementInternals ??= new WeakMap();
globalThis._elementInternals.set(this, internals);
}
}
);Das Zuweisen des Objekts zu einer Eigenschaft am Element funktioniert ebenfalls:
customElements.define(
'my-custom-button',
class MyCustomButton extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
this._internals.role = 'button';
}
}
);Neben der globalThis._elementInternals-Karte sucht Axe DevTools nach dem Objekt unter einem der folgenden Namen am Element:
_internals(empfohlen)internalsinternals_Symbol('internals')Symbol('privateInternals')
Eine Komponente, die ihre Internas wirklich privat hält, ist für Axe DevTools unsichtbar, und dies ist der häufigste Grund dafür, dass nach einem Upgrade keine Änderung sichtbar ist. Zwei Fälle, die überprüft werden sollten:
- Private Klassenfelder.
this.#internals = this.attachInternals()können von außerhalb der Klasse nicht gelesen werden, sodass kein Testwerkzeug sie sehen kann. Mehrere Komponentenbibliotheken verwenden dieses Muster. - Getter. Eine Eigenschaft, die als Accessor und nicht als einfacher Wert definiert ist, wird übersprungen, selbst wenn sie
_internalsgenannt wird. Weisen Sie das Objekt direkt zu.
In beiden Fällen gehört die Behebung in die Komponente und nicht in Ihre Testkonfiguration. Veröffentlichen Sie das Objekt in einer der oben genannten Formen oder rechnen Sie damit, dass das Element bewertet wird, als hätte es keine ARIA-Semantik.
Das Testen, ob Ihre Komponenten für Axe DevTools sichtbar sind, erfordert keinen Scan. In der Browser-Konsole auf einer Seite, die die Komponente verwendet, sollten globalThis._elementInternals?.get(document.querySelector('my-custom-button')) oder document.querySelector('my-custom-button')._internals ein ElementInternals-Objekt zurückgeben und nicht undefined.
Was Axe DevTools liest
Sobald das Objekt sichtbar ist, liest Axe DevTools die role-Eigenschaft und die ARIA-Eigenschaften, die den aria-*-Attributen entsprechen, wie ariaLabel für aria-label, ariaDescription für aria-description und ariaLabelledByElements für aria-labelledby. Diese Werte durchlaufen die gleichen Regeln, die gegen die entsprechenden Attribute ausgeführt würden, sodass ein benutzerdefiniertes Element, das role und ariaLabel über Internas setzt, auf einen zugänglichen Namen in gleicher Weise überprüft wird wie eines, das role und aria-label im Markup setzt.
Priorität
Werte, die im DOM vorhanden sind, setzen sich immer durch. Dies bedeutet, dass das Hinzufügen von Attributen zu Ihrem Markup eine zuverlässige Methode ist, um das zu überschreiben, was eine Komponente intern deklariert, und dass Internas niemals ein Problem verbergen, das im DOM sichtbar ist.
- Rolle. Die
rolevonElementInternalswird als die implizit-Rolle des Elements behandelt, dieselbe Stellung wie die eingebaute Rolle eines nativen Elements. Ein explizitesrole-Attribut am Element überschreibt es. - ARIA-Werte. Jeder Wert wird zuerst vom Attribut, dann von der entsprechenden Eigenschaft auf dem Element und erst dann von
ElementInternalsgelöst.
Einschränkungen
Unterstützung ist vorhanden, aber noch nicht vollständig, und die Lücken sollte man kennen, bevor man einen Scan interpretiert.
Regeln, die auf Attribute selektieren, passen nicht auf rein interne Elemente. Eine Reihe von Regeln identifizieren die Elemente, auf die sie angewendet werden, mit einem CSS-Selektor gegen das DOM. Da ein Element, dessen Semantik nur von ElementInternals stammt, kein role-Attribut hat, werden diese Regeln nie darauf angewendet. Zum Beispiel selektiert aria-required-attr [role], und aria-command-name selektiert [role="link"], [role="button"], [role="menuitem"]. Ein benutzerdefiniertes Element, das role = 'button' durch internals deklariert, wird von keiner Regel ausgewertet. Regeln, die die Rolle auflösen, anstatt einen Selektor abzugleichen, wie solche, die einen zugänglichen Namen berechnen, werden angewendet.
Rollwerte werden nicht validiert. Ein durch internals gesetzter role wird so verwendet, wie er ist. Ein ungültiger oder falsch geschriebener Wert wird nicht so gemeldet, wie es bei einem ungültigen role-Attribut der Fall wäre.
Einige Regeln werden nur teilweise angewendet. Regeln, die die Beziehung eines Elements zu seinen Kindern oder Vorfahren inspizieren, wie etwa aria-required-children, können ein rein internes Element möglicherweise nicht vollständig auswerten.
Insbesondere aufgrund der ersten Einschränkung sollten Sie bei einem Komponent, der seine Semantik nur durch internals deklariert, eher weniger Funde als das äquivalente Markup erwarten. Ein sauberer Scan eines solchen Komponents ist ein schwächerer Beweis als ein sauberer Scan eines mit Attributen.
Verwandte Seiten
- Anpassung von Regeln zur Auswahl der axe-core-Version, die Ihre Scans verwenden.
- Über Axe DevTools für Web-APIs für die vollständige Liste der unterstützten Sprachen und Frameworks.
- C# API-Dokumentation, Python-Übersicht, Erweiterte API-Nutzung mit Ruby, Java API-Übersicht und Node.js- und browserbasierte Tests für die Sprachbindungen, die dies unterstützen.
