Tastaturgesteuerte JavaScript-Komponenten

Tastaturgesteuerte JavaScript-Komponenten

├ťbersicht

Bei der Erstellung von Desktopkomponenten f├╝r Web-Applikationen, wie z.B. Men├╝s, Baumansichten, Richtext-Felder und Tab-Panels kommt in der Regel JavaScript zum Einsatz. Die Komponenten bestehen ├╝blicherweise aus <div>- und <span>-Elementen, die von Haus aus nicht die gleiche Funktionalit├Ąt wie echte Desktopkomponenten besitzen. Dieses Dokument beschreibt Techniken, die eingesetzt werden k├Ânnen, um JavaScript-Komponenten ├╝ber die Tastatur zug├Ąnglich zu machen.

Benutzung von tabindex

Das tabindex-Attribut wurde zu Beginn als Teil von HTML 4 eingef├╝hrt, um Entwicklern zu erm├Âglichen, die Reihenfolge f├╝r die Fokussierung von Elementen festzulegen, die vom Benutzer mit der Tastatur angesteuert werden. Das genaue Verhalten von tabindex wurde sp├Ąter etwas abge├Ąndert. Diese ├änderungen sind in der HTML 5-Spezifikation beschrieben. Alle bekannten Browser implementieren fortan das neue Design.

Die folgende Tabelle beschreibt das Verhalten von tabindex in modernen Browsern:

tabindex-Attribut Fokussierbar mit der Maus oder JavaScript ├╝ber element.focus() Tab-navigierbar
Nicht vorhanden Folgt der Festlegung f├╝r das Element f├╝r die Plattform ("Ja" bei Formularsteuerungen, Links, etc.). Folgt der Festlegung f├╝r das Element f├╝r die Plattform.
Negativ (z.B. tabindex="-1") Ja Nein; Entwickler muss auf Tasteneingaben reagieren und das Element ├╝ber focus() fokussieren.
Null (z.B. tabindex="0") Ja In der Tab-Ordnung relativ zur Position des Elements im Dokument.
Positiv (z.B. tabindex="33") Ja Wert von tabindex bestimmt die Position des Elements in der Tab-Ordnung: Im Allgemeinen werden Elemente vor solchen positioniert, bei denen tabindex="0" gesetzt ist oder die von Natur aus per Tab steuerbar sind; Elemente mit kleinere Werten werden vor solchen mit gr├Â├čeren Werten positioniert (ein Element mit tabindex="7" wird z.B. vor tabindex="11" positioniert)

Einfache Steuerungen

Damit z.B. eine einfache Tab-Komponente ├╝ber die Tastatur bedient werden kann, wird dem entsprechenden <div>- oder <span>-Element das tabindex-Attribut hinzugef├╝gt. Beim folgenden Beispiel wird diese Technik f├╝r eine Checkbox angewendet, die auf einem span-Element basiert.

Beispiel 1: Eine einfache Checkbox-Komponente mit einem Bild, welche um das tabindex="0" erweitert wurde und so auch ├╝ber die Tastatur gesteuert werden kann.

<!-- Ohne die tabindex-Attribute k├Ânnten die <span>-Elemente nicht mit der Tastatur fokussiert werden -->
<div>
    <span role="checkbox" aria-checked="true" tabindex="0">
        <img src="checked.gif" role="presentation" alt="" />
        Include decorative fruit basket
    </span>
</div>
<div>
    <span role="checkbox" aria-checked="true" tabindex="0">
        <img src="checked.gif" role="presentation" alt="" />
        Include singing telegram
    </span>
</div>
<div>
    <span role="checkbox" aria-checked="false" tabindex="0">
        <img src="unchecked.gif" role="presentation" alt="" />
        Require payment before delivery
    </span>
</div>

Gruppieren von Steuerungselementen

F├╝r die Gruppierung von Komponenten, wie z.B. Men├╝s, Tableisten, Grids oder Baumansichten, sollte das Elternelement in die Tab-Ordnung aufgenommen werden (tabindex="0"). Au├čerdem sollte jede(s) untergeordnete Auswahl/Tab/Zelle/Reihe aus der Tabordnung entfernt werden (tabindex="-1"). Die untergeordneten Elemente sollten vom Benutzer ├╝ber die Pfeiltasten angesteuert werden k├Ânnen (Eine ausf├╝hrliche Beschreibung der Tastaturunterst├╝tzung, die im Allgemeinen f├╝r bestimmte Komponenten erwartet wird, finden Sie im DHTML Style Guide).

Beim n├Ąchsten Beispiel wird diese Technik bei einer Men├╝steuerung eingesetzt. Sobald der Fokus der Tastatur das <ul>-Element erreicht, muss der JavaScript-Entwickler den Fokus programmatisch steuern und auf das Dr├╝cken der Pfeiltasten reagieren. Techniken f├╝r die Steuerung des Fokus innerhalb von Komponenten, sind im Abschnitt "Steuerung des Fokus innerhalb von Gruppen" weiter unten beschrieben.

Beispiel 2: Eine Men├╝steuerung bei der mit tabindex die Tastaturnavigation gesteuert wird.

<ul id="mb1" tabindex="0">
  <li id="mb1_menu1" tabindex="-1"> Font
    <ul id="fontMenu" title="Font" tabindex="-1">
      <li id="sans-serif" tabindex="-1">Sans-serif</li>
      <li id="serif" tabindex="-1">Serif</li>
      <li id="monospace" tabindex="-1">Monospace</li>
      <li id="fantasy" tabindex="-1">Fantasy</li>
    </ul>
  </li>
  <li id="mb1_menu2" tabindex="-1"> Style
    <ul id="styleMenu" title="Style" tabindex="-1">
      <li id="italic" tabindex="-1">Italics</li>
      <li id="bold" tabindex="-1">Bold</li>
      <li id="underline" tabindex="-1">Underlined</li>
    </ul>
  </li>
  <li id="mb1_menu3" tabindex="-1"> Justification
    <ul id="justificationMenu" title="Justication" tabindex="-1">
      <li id="left" tabindex="-1">Left</li>
      <li id="center" tabindex="-1">Centered</li>
      <li id="right" tabindex="-1">Right</li>
      <li id="justify" tabindex="-1">Justify</li>
    </ul>
  </li>
</ul>

Deaktivierte Steuerungen

Wenn Sie ein Steuerelement deaktivieren, sollte dieses aus der Tab-Ordnung entfernt werden, indem tabindex="-1" gesetzt wird. Elemente, die Teil einer Komponentengruppe (wie z.B. Men├╝punkte in einem Men├╝) sind, sollten ├╝ber die Tastatur ansprechbar bleiben.

Steuerung des Fokus innerhalb von Gruppen

Wenn ein Benutzer den Fokus per Tab von einem Element wegbewegt, sollte der Fokus zu dem Element, das zuvor fokussiert war - z.B. einer Baumkomponente oder Gridzelle - zur├╝ckkehren. Es existieren zwei verschiedene Techniken, um dies zu bewirken:

  1. Verschiebung von tabindex: Programmatische Bewegung des Fokus
  2. aria-activedescendent: Verwaltung eines "virtuellen" Fokus

Technik 1: Verschiebung von tabindex

Setzt man tabindex f├╝r das fokussierte Element auf "0", wird das ausgew├Ąhlte Element innerhalb der Gruppe erneut fokussiert, wenn der Benutzer den Fokus per Tab fortbewegt und dann zu diesem Element zur├╝ckkehrt. Beachten Sie, dass bei der Aktualisierung von tabindex auf 0 f├╝r des zuvor selektierte Element tabindex="-1" gesetzt werden muss. Diese Technik wird auch verwendet, wenn auf Tastendr├╝cke reagiert und der Fokus programmatisch weiterbewegt wird. Der tabindex wird dann entspechend aktualisiert, um das aktuell fokussierte Element anzuzeigen. Dies l├Ąsst sich wie folgt umsetzen:

Jeweils ein keydown-Hander wird mit einem Element der Gruppe verkn├╝pft. Wenn der Benutzer eine Pfeiltaste dr├╝ckt, um ein anderes Element anzusteuern, passiert Folgendes:

  1. Das neue Element wird codegesteuert fokussiert.
  2. Der tabindex des fokussierten Elements wird auf "0" gesetzt.
  3. Der tabindex des zuvor fokussierte Elements wird auf "-1" gesetzt.

Hier finden Sie ein Beispiel f├╝r eine WAI-ARIA Baumansicht bei der diese Technik eingesetzt wird.

Tipps
Mit element.focus() den Fokus setzen

Benutzen Sie nicht die Funktionen createEvent(), initEvent() und dispatchEvent() um ein Element zu fokussieren. DOM-Focus-Events arbeiten nur informell: Sie werden vom System erzeugt, wenn ein Element fokussiert wird, aber nicht verwendet, um den Fokus zu setzen. Greifen Sie stattdessen auf element.focus() zur├╝ck.

Mit onfocus den Fokus ├╝berpr├╝fen

Gehen Sie nicht davon aus, dass Fokus├Ąnderungen allein ├╝ber die Tastatur oder Maus initiiert werden: Assistierende Technologien, wie z.B. Screenreader, sind in der Lage den Fokus f├╝r jedes fokussierbare Element zu setzen. Benutzen Sie daher onfocus und onblur um Fokus├Ąnderungen zu verfolgen.

onfocus und onblur k├Ânnen nun mit jedem beliebigen Element verwendet werden. Es existiert jedoch kein Standard-DOM-Interface, um den aktuellen Fokus im Dokument abzufragen. Wenn man den Fokus verfolgen m├Âchte, muss der aktuelle Zustand in einer JavaScript-Variablen hinterlegt werden.

Technik 2: aria-activedescendant

Bei dieser Technik wird ein einzelner Event-Handler mit der Container-Komponente verkn├╝pft und aria-activedescendant dazu benutzt, um einen "virtuellen" Fokus zu verwalten. (Mehr Informationen ├╝ber ARIA finden Sie indieser ├ťbersicht).

The aria-activedescendant property identifies the ID of the descendent element that currently has the virtual focus. The event handler on the container must respond to key and mouse events by updating the value of aria-activedescendant and ensuring that the current item is styled appropriately (for example, with a border or background color). See the source code of this ARIA radiogroup example for a direct illustration of how this works.

Die Eigenschaft aria-activedescendent enth├Ąlt die ID des untergeordneten Elements, das aktuell fokussiert ist. Der Event-Handler des Containers muss auf Tastatur- und Mauseingaben reagieren, den Wert von aria-activedescendent aktualisieren und sicherstellen, dass die Darstellung des Elements entsprechend angepasst wird (z.B. Rahmen oder Hintergrundfarbe). Ein konkretes Beispiel f├╝r diese Technik liefert der Quellcode des ARIA-Radiogruppen-Beispiels.

Tipps
scrollIntoView

Note that the use of this pattern requires the author to ensure that the current focused widget is scrolled into view. You should be able to use the element.scrollIntoView() function, but we recommend confirming this works for you in your target browsers using the quirksmode test.Bei der Benutzung dieses Musters muss der Entwickler sicherstellen, dass das aktuell fokussierte Element in Sichtweite gescrollt wird. F├╝r diesen Zweck kann die Funktion element.scrollIntoView() eingesetzt werden. ├ťberpr├╝fen Sie jedoch unbedingt mit dem Quirksmode-Test, ob dies f├╝r ihre Browser, die unterst├╝tzt werden sollen, fehlerfrei funktioniert.

Probleme

Allgemeine Richtlinien

Benutzung von onkeydown, um auf Tastendr├╝cke zu reagieren (nicht onkeypress)

Der Internet Explorer f├╝hrt keypress-Events f├╝r nicht-alpahnumerische Zeichen nicht aus. Benutzen Sie stattdessen das onkeydown-Event.

Tastatur- und Mausbedienung sollte konsistent sein

Um sicherzustellen, dass Benutzereingaben unabh├Ąngig vom Eingabeger├Ąt konstistent sind, sollten Tastatur- und Maus-Eventhandler denselben Code verwenden. Zum Beispiel sollte der Code, womit der tabindex oder das Aussehen festgelegt wird, wenn die Pfeiltasten benutzt werden, auch f├╝r die Mausklick-Handler verwendet werden, damit dieselben ├änderungen stattfinden.

Aktivierung von Elementen per Tastatur

Damit die Tastatur f├╝r die Aktivierung von Elementen benutzt werden kann, sollte alle Handler, die mit der Mausevents verkn├╝pft sind, auch mit Tastaturevents verkn├╝pft werden. Soll z.B. mit der Enter-Taste ein Element aktiviert werden k├Ânnen, welches ├╝ber einen Maushandler onclick="doSomething()" mit der Maus verkn├╝pft ist, dann sollte die Funktion doSomething() auch ├╝ber ein keydown-Event mit der Tastatur verkn├╝pft werden: onkeydown="return event.keyCode != 13 || doSomething();".

Verwenden Sie nicht :focus f├╝r das Styling (falls Kompatibilit├Ąt mit IE 7 und ├Ąltereren Browsern notwendig)

Der Internet Explorer 7 und ├Ąltere Versionen unterst├╝tzen den Pseudoselektor :focus nicht. Aus diesem Grund sollte er f├╝r die Gestaltung von fokussierten Elementen nicht verwendet werden. Stattdessen kann die Darstellung ├╝ber einen onfucus-Eventhander ver├Ąndert werden, z.B. indem ein CSS-Style Name dem class-Attribut hinzugef├╝gt wird.

Kontinuierliches Anzeigen des Fokus f├╝r Elemente mit tabindex="-1", die programmatisch fokussiert werden

Der Internet Explorer zeigt die Fokusumrandung f├╝r Elemente nicht automatisch an. Die Hervorhebung des fokussierten Elementes muss daher per JavaScript, entweder durch die ├änderung der Hintergrundfarbe (z.B. this.style.backgroundColor = "gray") oder Anzeige eines gepunkteten Rahmen (z.B. this.style.border = "1px dotted invert") erfolgen. Entscheiden Sie sich f├╝r die zweite Vorgehensweise, sollten die Elementen von Anfang an einen unsichtbaren 1px-Rahmen besitzen, damit sie nicht gr├Â├čer werden, wenn der Rahmen angezeigt wird (Rahmen nehmen Platz in Anspruch und beim IE sind CSS-Outlines nicht implementiert).

Verwendete Tastendr├╝cke sollten keine Browserfunktionen ausl├Âsen

Wenn eine Komponente auf Tastendr├╝cke reagiert, sollte verhindert werden, dass der Browser diese Tastendr├╝cke verarbeitet (z.B. Scrollen mit den Pfeiltasten), indem bei Event-Handlern ein Return-Code angegeben wird. Der R├╝ckgabewert false verhindert, dass das Event an den Browser weitergereicht wird.

Hierzu ein Beispiel:

<span tabindex="-1" onkeydown="return handleKeyDown();">

Gibt die Funktion handleKeyDown() den Wert false zur├╝ck, wird das Event ├╝bernommen und der Browser so davon abgehalten auf den Tastendruck zu reagieren.

Abweichendes Verhalten bei wiederholten Tastendr├╝cken

Je nach Betriebssystem kann es leider vorkommen, dass bei wiederholten Tastendr├╝cken onkeydown-Events wiederholt ausgef├╝hrt werden oder auch nicht.