Als ich meine Webseite und mein Blog einem Relaunch unterzog war mir klar, daß das Endergebnis nicht in Stein gemeißelt war. Es sollte es auch nicht sein. Natürlich kann man oft an einer Webseite Verbesserungen und Veränderungen vornehmen. Als eine der Verbesserungen plante ich von Anfang an die Einführung von WAI-ARIA ein. Mit diesem gar nicht mehr so neuen Webstandard kann man Screenreadern Feedback u.a. bei dynamischen Elementen der Webseite geben. Da ich hin und wieder Elemente zusammengeklappt lade und diese aufklappbar sind, war es in meinen Augen notwendig, Screenreadern einen Hinweis darauf zu geben.
Marco Zehe hat in seinem Blog freundlicherweise beschrieben, welche Elemente welche Attribute bekommen müssen. Diese Technik ist nur sinnvoll und notwendig beim Einsatz von Javascript. Ich möchte im Folgenden beschreiben, welche Änderungen ich vorgenommen habe, um das Ziel zu erreichen.
Die Klapplisten haben drei zu beachtende Aspekte:
- Die Listencontainer sollen zusammengeklappt sein, wenn die Seite läd. Dies soll aber nur dann passieren, wenn Javascript aktiv ist, denn schließlich benötige ich Javascript zum Öffnen der Container.
- Die Container sollen separat auf- und zuklappbar sein. Es soll keine gegenseitige Abhängigkeit herrschen.
- Das Auf- und Zuklappen der Listen soll sich dem Screenreader mitteilen.
Es versteht sich von selbst, daß der Code einfach, semantisch und logisch sein soll.
Wenn die Seite läd, lasse ich mittels Javascript eine Klasse js
an das HTML-Element hängen:
<script type="text/javascript"> document.documentElement.className += "js"; </script>
Danach sorge ich mittels CSS dafür, daß die betreffenden Listen ausgeblendet sind. Durch die Kaskade über die Klasse js
sorge ich dafür, daß die Listen nur im Falle der Existenz von Javascript ausgeblendet werden. Denn nur dann haben sie eine Chance, wieder eingeblendet zu werden.
<style type="text/css" media="screen">
.js .toggle > ul { display: none;}
</style>
Die Container mit den Listen sind wie gewünscht einfach und logisch aufgebaut, was angesichts des einfach strukturierten Inhalts auch kein Wunder ist. Ein DIV
-Container umfaßt eine Überschrift und eine Liste. Der Container wird benötigt, um den Kontext für das Javascript zu schaffen und für den Rahmen, der den Inhalt optisch zusammenhält. Die Überschrift ist zusätzlich noch der Auslöser für die Klappfunktion. Der eigentliche Inhalt wird in einer Liste transportiert. Das ist allerdings kein Muss.
Ich nutze jQuery für die Klappfunktion. In seiner ursprünglichen Form – ohne die WAI-ARIA-Erweiterungen – sah das Skript folgendermaßen aus:
$('.toggle h3').click(function(){
$(this).siblings('ul').slideToggle();
$(this).toggleClass('zuklappen');
})
Der Code sollte einfach zu verstehen sein. Bei jedem Klick auf eine Überschrift, die sich unter einem Element mit der Klasse toggle
befindet, wird das direkt folgende Geschwisterelement, das eine ungeordnete Liste sein muss, auf- oder zugeklappt, je nachdem, in welchem Status es sich befindet. Zusätzlich wird an der Überschrift die Klasse zuklappen
hinzugefügt oder entfernt. Die toggle
-Funktionen bei jQuery sind einfach und elegant benutzbar. Wegen der WAI-ARIA-Erweiterung mußte ich den Code ein wenig umschreiben und erweitern. Herausgekommen ist folgender Code:
$('.toggle h3').each(function() {
var thingy = $(this);
var sibid = thingy.next().attr('id');
thingy.attr({
'aria-expanded': 'false',
'aria-controls': sibid
})
thingy.click(function() {
$(this).siblings().slideToggle('fast', function(){
if(!(thingy.attr('aria-expanded') == 'true')) {
thingy.attr('aria-expanded', 'true');
} else {
thingy.attr('aria-expanded', 'false');
}
});
});
});
Die oben genutzte kurze Version reichte nicht mehr, da sie nur auf Klick Dinge tut. Mittels jQuery sollten aber auch unabhängig von der konkreten Aktion Attribute zu speziellen Elementen hinzugefügt werden. Also gehe ich erst mit der Funktion each()
alle Überschriften in den Klappboxen durch. Bei diesem Durchgang werden den Überschriften zwei Attribute mit passenden Parametern hinzugefügt. Ein Parameter ist der Inhalt der ID
der folgenden Liste. Diese ID
wird in einer Variable gespeichert und dann zugewiesen. Bei Klick auf eine Überschrift prüfe und ändere ich dann den Inhalt des Attributes aria-expanded
.
Die so gefundene Lösung ist zwar eindeutig komplexer, als die ursprüngliche Lösung. Sie ist aber noch immer kein Hexenwerk. Mit ein bischen mehr Mühe habe ich so eine weitere kleine Barriere meiner Webseite entfernt. Sicherlich werde ich noch ein paar weitere kleine Details finden, die ich u.a. mit WAI-ARIA verbessern kann. Ich denke, daß diese Lösung auch bei Deinem nächsten Projekt nützlich sein kann.
11. März 2010 um 22:10 Uhr
Nur funktioniert das nicht was du da schreibst. Marco hat sich, so wie ich das damals gelesen habe, verkürzt ausgedrückt. Da er in einem älteren Artikel erwähnt hat, daß die a11y-Entwickler bei Mozilla das aria-expanded-Attribut – entgegen der aria-Spezifikation – erweitert haben (geht auch bei button), habe ich nicht schon da „klug geschissen“ :-).
Gründe:
1. aria-expanded ist kein Universal-Attribut. Damit das aria-expanded-Attribut auch richtig weitergeleitet wird, muß das Element eine entsprechende Rolle haben. Diese Rollen werden durch die aria-Spezifikation festgelegt. Wie gesagt, Mozilla hat sich entschieden, daß aria-expanded-Attribut auch in anderen Fällen „weiterzuleiten“. (Das war die richtige Entscheidung. Meiner Meinung nach sollten eh alle Aria-Eigenschaften universal einsetzbar sein. (Ob sie dann funktionieren/richtig vom Screenreader interpretiert werden können, ist dann eine andere Frage.)
Damit du aber von diesem Feature profitieren kannst, muß da natürlich eine Rolle ran, die das expanded-Attribut unterstützt.
2. Du „mißbrauchst“ eine h3 als klickbares Element. Das ist bei ausgeschaltetem JS richtig, bei eingeschaltetem ‚falsch‘, auch das schreit nach einer Veränderung der Rolle. (Der gemeine Screenreader errät nur, aufgrund eines schlechten Workarounds, daß die h3 wahrscheinlich klickbar ist. In Zeiten, in denen Entwickler vermehrt Event-Delegation einsetzen, ist dieser Workaround nicht mehr zuverlässig und man sollte sich nicht auf ihn verlassen.)
3. Ein Tastaturnutzer würde sich freuen, wenn die h3-Überschrift fokusierbar, der focus gestyled und auch durch Tastatur einen klick auslösen würde.
Script-Vorschlag für zugängliches Toggle
11. März 2010 um 23:40 Uhr
Hallo Alexander. Marco Zehe hatte meine Implementierung getestet und für funktionsfähig empfunden. Aber es kann natürlich sein, daß das nicht in jedem Screenreader funktioniert. Deine Version ist wesentlich umfangreicher als meine. Ich muss sie mir mal in Ruhe anschauen, um sie zu verstehen. Wenn ich darf, würde ich sie bei mir einbauen. Dann spätestens ist es aber wohl doch Zeit für eine externe Datei. Oder ich versuche den Code zu komprimieren. Die wenigen Zeilen, die ich bisher geschrieben hatte, waren mir eine externe Datei nicht wert.
Würde es nicht genügen, zusätzlich zu den beiden jetzt schon hinzugefügten Attributen noch das
role
-Attribut hinzuzufügen?Und würde es bei der Überschrift nicht genügen, mittels jQuery einen Fake-Link einzufügen? Dann stellt sich aber immernoch die Frage, wohin dieser Link führen soll. Ich stehe nicht auf Fake-Links. Das mag eine Stilfrage sein. Aber ich behalte sie gerne bei, bis ich einen vernünftigen Grund finde, die Stilfrage anders zu bewerten. Den Fokus kann ich noch hinzufügen, gute Idee. Vielen Dank für Deinen Input.
12. März 2010 um 0:32 Uhr
Hi nochmal,
ja, es sollte absolut reichen, wenn die h3 eine
role="button"
und eintabindex="0"
bekommt.Allerdings ist ein click-Listener hier nicht mehr ausreichend, da das click-Event nur bei „natürlich“ klickbaren Elementen ein eingabeunabhängiges Event darstellt (außer man verwendet Screenreader oder andere ATs, die dieses Event eingabeunabhängig machen. (Das Script fügt daher ein neues Event hinzu namens ‚ariaclick‘.))
Was das Testen mit Screenreader angeht, so war dein Script SR-zugänglich. Lediglich hat die Aria-Verbesserung keine solche Verbsserung gezeigt. Ich kann mich jetzt irren (war nämlich nur ein voreingenommener Schnelltest, in dem ich meine anfängliche Vermutung, daß das nicht funktioniert, bestätigt sehen wollte): aber das dürfte in praktisch allen Screenreadern der Fall sein. Laut MSAA-Inspect hat FF 3.6 unter WinXP das aria-expanded gar nicht übertragen und weder Jaws 10 noch NVDA haben sich das bei mir auf anderem Wege gezogen. Im IE8 habe ich gar nicht erst getestet, da er hier das expanded eh nur bei trees, tabs und Konsorten beherrscht.
Letztendlich bin ich durch deinen Beitrag auf einen neuen/alten overflow-hidden Jaws/FF-Bug gestoßen. Danke, es werden Tage der Verzweiflung folgen.
12. März 2010 um 10:00 Uhr
Hi zusammen!
Es ist richtig, dass aria-expanded nicht auf alles anwendbar ist. Siehe hierzu die Beschreibung. Die Spezifikation fasst es inzwischen aber so weit, dass wir uns im entsprechenden Bug dazu entschlossen haben, es als universelles Attribut zu behandeln. Und streng genommen ist Jens‘ Anwendung sogar innerhalb der Spezifikation, denn „Sectionhead“ ist explizit als Rolle zugelassen. 🙂