Entries tagged as unobtrusive

2009-02-07 jQuery Accessible Tabs - How to make tabs REALLY accessible

translations: german

While a lot of Tabs-Scripts claim to be accessible it turns out, most of them are really not. While developing this jQuery Plugin with my coworker Artur Ortega, we tried to find a single existing Javascript powered Tabs-Interface that Artur, using his Screenreader, would actually be able to use properly. We eventually gave up the search.

The one Problem even the better ones have is the missing Feedback of the content change. Most of the tabs scripts change the style of the tabs and the visibility of their corresponding content but leave the user just where he was - on the tab-link - not knowing that something happened (just like clicking on a, ever so popular, inactive link (a href="#")).

This is also the big difference this Script makes. While the user experience for users without visual impairment is exactly the same, there's a lot happening under the hood. But let's start from the beginning.

jQuery Accessible Tabs uses a very simple and flexible HTML markup as it's base to build upon. All it needs it's a wrapper containing Headlines and content elements one after the other. This provides a nice non-javascript fallback that does not look like something is missing or broken.


        <div class="tabs">
            <h2>some dummy headline</h2>
            <div class="tabbody">
                <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>

                <h3>Lorem ipsum</h3>
                <p>Nullam malesuada suscipit pede. Nullam ipsum lacus, varius</p>

            </div>
            <h2>another dummy headline</h2>
            <div class="tabbody">
                <p>Integer tincidunt. Cras dapibus. Vivamus elementum nisi.</p>

                <p>Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel.</p>

            </div>
            <h2>anything else</h2>
            <div class="tabbody">
                <p>Here could be your content</p>

            </div>
        </div>
     

A simple jQuery call then transforms this to the accessible Tabs:


        $(document).ready(function(){
                $('.tabs').accessibleTabs();
        });
     

To not only be accessible but also to be as flexible as possible the script allows configurations to be passed to.


    $('.tabs').accessibleTabs({
        // Classname to apply to the div that is wrapped around
        // the original Markup
        wrapperClass: 'content',
        // Classname to apply to the LI of the selected Tab
        currentClass: 'current',
        // Tag or valid Query Selector of the Elements to Transform the
        // Tabs-Navigation from (originals are removed)
        tabhead: 'h4',
        // Tag or valid Query Selector of the Elements to be treated as
        // the Tab Body
        tabbody: '.tabbody',
        // can be 'fadeIn', 'slideDown', 'show'
        fx:'show',
        // speed (String|Number): 'slow', 'normal', or 'fast') or the number of
        // milliseconds to run the animation
        fxspeed: 'normal',
        // text to indicate for screenreaders which tab is the current one
        currentInfoText: 'current tab: ',
        // Definition where to insert the Info Text.
        // Can be either 'prepend' or 'append'
        currentInfoPosition: 'prepend',
        // Class to apply to the span wrapping the CurrentInfoText
        currentInfoClass: 'current-info'
    });
     

So, why is this Tabs-Script more accessible than others?

The main thing this Script does better than the others is providing a click feedback for Screenreader Users. When the user clicks on one of the tabs there's actually a navigation going on on the page.

Every link in the tabs is pointing to an actually focusable content. To allow this, we create a named anchor inside of the tabs content. This anchor, as it has no href property, is not focusable by default though. To make it focusable we gave it a tabindex="0". Why 0? Because a tabindex of 0 does not change the natural tab flow of the page but it makes an element focusable which is not able to receive focus by default.


    <h4>
        <a id="accessibletabscontent" name="accessibletabscontent" class="accessibletabsanchor" tabindex="0">
            some dummy headline
        </a>
    </h4>
     

Inside of the named anchor we add the same text as the tab that was just clicked and wrapped it into a headline element. This provides a very nice user experience for screenreader users, as it nicely confirms that you actually jumped into a new content of the page.

The other thing that adds benefit for screenreader users is a little text that indicates the currently selected tab. It defaults to "current tab: " followed by the default text of the tab. For internationalisation reasons this text as well as the text position (either before or after) can easily be configured.

Problem: Focussing hidden or recently hidden Elements

During the testing of the tabs we discovered a very interesting, yet very annoying, behaviour of the Screenreader Jaws (and probably others too). We wanted to focus the headline in the content of the current tab after clicking the tab which made the content visible. Everytime we tested, the Screenreader was unable to find the element to focus on and simply jumped to the end of the page or randomly somewhere else. We discovered that this is only happening when the focus target was recently hidden. This phenomenon is caused by the screenreaders virtual buffer, an internal copy of the actual DOM in which the Screenreader user navigates. The virtual buffer does regularly update itself from the Browser DOM but there's always a delay.

To work around this issue we used a different approach. The named anchor we're linking to is not actually in the hidden tab content but before it in the DOM of all of the contents and hidden offscreen. Also actually every link in the tabs is pointing to the same anchor. We're simply dynamically rewriting the headline text on the fly and show and hide the contents accordingly. The user experience is just the same. The screenreader user clicks on the tab, follows the link and finds the linked content starting with a corresponding headline.

You can see the script in action in in many different Examples here. This plugin is also part of the The CSS Framework Yaml

You can download the latest version of this script including the demos here.

Update:

Jason Kiss wrote this excellent followup about how to make this even better

His enhancements are now also in the official repository

You can always find the latest Code in the Accessible Tabs github repository

2009-02-07 jQuery Accessible Tabs - Wie man Tabs WIRKLICH zugänglich macht

Während viele Tabs-Scripts behaupten zugänglich zu sein sind es die meisten leider weit davon entfernt. Während ich dieses jQuery Plugin zusammen mit meinem Kollegen Artur Ortega entwickelte, suchten wir nach existierenden Javascript Tabs die Artur mit seinem Screenreader tatsächlich bedienen kann. Wir gaben die Suche irgendwann auf.

Das Problem, dass selbst die besseren Scripts haben, ist die Fehlende Rückmeldung an den Nutzer, dass tatsächlich etwas Passiert. Die meisten Tabs Scripts ändern das Aussehen der Tabs und die Sichtbarkeit der zugehörigen Inhalte aber lassen den Nutzer da zurück wo er war - auf dem Tab auf den geklickt wurde - ohne Ahnung was gerade passiert ist (vergleichbar mit einem Klick auf die immer noch viel zu beliebten "Blinden Links" (a href="#")).

Das ist auch genau der große Unterschied den dieses Script macht. Während das Verhalten für Nutzer ohne Sehbehinderung exakt die gleiche ist passiert sehr viel unter der Haube. Aber erstmal zurück zum Anfang.

jQuery Accessible Tabs benutzt ein sehr einfaches und flexibles HTML Markup als Basis. Alles was es braucht ist ein Wrapper mit Headlines und Inhalts-Elementen nacheinander. Die einfachste und bestmöglichste Alternative ohne Javascript ohne Auszusehen als würde etwas fehlen oder etwas währe kaputt.


    <div class="tabs">
        <h2>eine Beispielüberschrift</h2>
        <div class="tabbody">
            <p>Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</p>
            <h3>Lorem ipsum</h3>
            <p>Nullam malesuada suscipit pede. Nullam ipsum lacus, varius</p>
        </div>
        <h2>noch eine Beispielüberschrift</h2>
        <div class="tabbody">
            <p>Integer tincidunt. Cras dapibus. Vivamus elementum nisi.</p>
            <p>Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel.</p>
        </div>
        <h2>alles andere</h2>
        <div class="tabbody">
            <p>Hier könnte Ihr Inhalt stehen</p>
        </div>
    </div>
 

Ein einfacher jQuery Aufruf transformiert das Markup in accessible Tabs:


    $(document).ready(function(){
        $('.tabs').accessibleTabs();
    });
 

Um nicht nur so zugänglich sondern auch so flexibel wie möglich zu sein, kann das Script mit verschiedensten Einstellmöglichkeiten konfiguriert werden.


$('.tabs').accessibleTabs({
    // Der Name der Klasse die dem Div zugewiesen
    // welche um das Markup herumgeschrieben wird
    wrapperClass: 'content',
    // Der Name der Klasse die das aktuelle Tab markiert
    currentClass: 'current',
    // Tag oder valider Query Selector der Elemente 
    // aus denen die Tabs Navigation erzeugt wird
    // (die Originale werden entfernt)
    tabhead: 'h4',
    // Tag oder valider Query Selector der Elemente die
    // als Inhalte der Tabs genutzt werden sollen
    tabbody: '.tabbody',
    // Anzeigeeffekte:  'fadeIn', 'slideDown' oder 'show'
    fx:'show',
    // Geschwindigkeit (String|Number): 'slow', 'normal', oder 'fast')
    // oder die Milisekunden die die Anzeigeeffekte dauern sollen
    fxspeed: 'normal',
    // Text um Screenreadern anzuzeigen welches der ausgewählte Tab ist
    currentInfoText: 'current tab: ',
    // Definition wo der Text eingefügt wird
    // Entwender 'prepend' oder 'append'
    currentInfoPosition: 'prepend',
    // Klasse des span mit dem Infotext
    currentInfoClass: 'current-info'
});
 

Also gut, warum ist dieses Script zugänglicher als andere?

Das, was dieses Script hauptsächlich besser macht als die anderen ist ein Feedback für Nutzer von Screenreadern nach dem Klick. Wenn der Nutzer auf einen der Tabs klickt wird tatsächlich auf der Seite navigiert.

Jeder Link in den Tabs führt tatsächlich zu einem fokusierbaren Inhalt. Um dies zu ermöglichen, erzeugen wir einen benannten Anker in dem zugehörigen Inhalt des Tabs. Dieser Anker, da er keine href-Egenschaft hat, kann von Haus aus aber keinen Fokus erhalten. Um dies zu ermöglichen wird ihm die Eigenschaft tabindex="0" zugewiesen. Warum 0? Weil ein Tabindex von 0 nicht die natürliche Tabordnung des Dokumentes verändert aber dem zugewiesenen Element trotzdem ermöglicht Tab-Fokus zu bekommen.


<h4>
    <a id="accessibletabscontent" name="accessibletabscontent" class="accessibletabsanchor" tabindex="0">
        Eine Beispielüberschrift
    </a>
</h4>
 

In dem benannten Anker wird der selbe Text wie im Tab eingefügt welches gerade geklickt wurde und das ganze mit einer Headline umklammert. Dies stellt eine sehr angenehme Erfahrung für die Nutzer von Screenreadern dar, da es auf nette Art und Weise bestätigt, dass man gerade zu einem anderen Inhalt auf der Seite gesprungen ist.

Ein weiteres Zusatzfeature für Screenreader Nutzer ist ein kleiner Text der auf den aktuell ausgewählten Tab kennzeichnet. Standardmäßig lautet dieser Text "current tab: " gefolgt von dem Standardtext des Tabs. Dieser Text, ebenso wie seine Position (entweder davor oder danach) ist aber sehr leicht internationalisierbar.

Problem: Das Fokussieren von versteckten oder eben noch versteckt gewesenen Elementen

Während dem Testen der Tabs stießen wir auf ein sehr interessantes und ebenso störendes Verhalten des Screenreaders Jaws (und sehr wahrscheinlich auch von anderen). Wir wollten auf die Headline in dem Inhaltselement eines Tabs fokussieren nachdem es eingeblendet wurde. Bei jedem Test war der Screenreader nicht in der Lage das entsprechende Element zu finden und sprach statt dessen um Ende des Dokumentes oder einer anderen zufälligen Position. Dieses Phänomen wird durch den virtuellen Buffer des Screenreaders verursacht, einer internen Kopie des DOMs in dem der Screenreader navigiert. Der virtuelle Buffer gleicht seinen Inhalt regelmäßig mit dem DOM des Browsers ab aber dies ist stets erst nach einer Verzögerung.

Um um dieses Problem herum zu arbeiten nutzen wir einen anderen Lösungsansatz. Der benannte Anker auf den wir verlinken ist tatsächlich nicht in dem versteckten Inhaltselement sondern im DOM davor und "offscreen" (position:absolute;left:-999em) versteckt. Tatsächlich zeigt jeder Tab auf den exakt selben Anker. Wir schreiben den Inhalt des Headline-Elementes einfach jedes mal neu und blenden das zugehörige Inhaltselement entsprechend ein oder aus. Das empfundene Verhalten ist genau das gleiche. Der Screenreader Nutzer klickt auf den Tab, folgt dem Link und findet den verlinkten Inhalt mit der entsprechenden Headline.

Man kann sich das Script hier in in vielen verschiedenen Beispielen in Aktion ansehen. Das jQuery Plugin ist ebenfalls seit der Version 3.1.1 Teil des CSS Framework Yaml.

Man kann das script zusammen mit den demos hier herunterladen. Der gesamte Code ist ebenfalls auf github.

2007-10-16 Barrierearmes jQuery Dropdown Menü

Letzte Woche erhielt ich eine schriftliche Einladung vom MAIN_blogs-Team an der Accessibility Blog Parade teilzunehmen.

Wenn man schon so nett eingeladen wird, und es auch noch um ein so engagiertes und sinnvolles Projekt handelt, kann man natürlich unmöglich nein sagen :-)

Mein Beitrag zur Blog Parade und zur verbesserten Barrierefreiheit ist (m)ein:

Barrierearmes jQuery Dropdown Menü

Das jQuery Plugin basiert auf dem "accessible onchange select menu" von The Man in Blue.

Dieses Script besticht durch die intuitiven Auswahlmöglichkeiten eines Menüpunktes, in einem Select-Formular-Element, rein über die Tastatur. Bestätigt wird die Auswahl durch die Enter-Taste oder über das Verlassen des Elements mit der Tabulator-Taste. Die Auswahl kann durch die Escape-Taste abgebrochen werden.

Das einzige, aber leider sehr große, Problem dieses Scripts ist die fehlende Funktionalität ohne Javascript (damit büßt das Script, meiner Meinung nach, leider auch vollständig die Bezeichnung "Accesible" ein). Ohne Javascript hat der Nutzer nämlich leider überhaupt keine Möglichkeit das Formular abzuschicken.

Für ein kommunales Projekt, das leider erst in 6-7 Monaten online gehen wird, habe ich also ein Dropdown Menü entwickelt, dass auf die gleiche einfache Art bedienbar ist, aber bei nicht vorhandenem Javascript einen ordentlichen Absenden-Button anbietet.

jQuery-typisch kann das Script sehr einfach eingebaut werden. Dieser simple jQuery Aufruf fügt dem darauf folgendem HTML die notwendige Funktionalität hinzu:


$(function() {
        $('form').dropdownmenu();
});
 

<form action="http://blog.ginader.de/" name="dropdownmenu1" method="get">
        <fieldset>
                <legend>
                        An example form
                </legend>
                <label for="selector">
                        An example select menu
                </label>
                <select id="selector" name="selector">
                        <option value="0">Select Option</option>
                        <option value="1">Option 1</option>
                        <option value="2">Option 2</option>
                </select>
                <input type="submit" name="submit" value="go" />
        </fieldset>
</form><p>
 

Hier gibt es eine funktionierende Demo,
hier kann man das Script gezippt herunterladen,
und hier kann man das Script in Subversion anschauen, auschecken oder Bugs melden.

2007-05-11 Vorträge zu Unobtrusive Javascript und jQuery

Wie schon berichtet hatte mich die PHP Usergroup Frankfurt eingeladen, in meiner Eigenschaft als Webkraut, über unobtrusive Javascript zu reden. Darren von der Usergroup hatte mich, (nachdem er meine jQuery-Einführung auf dem Barcamp Frankfurt gesehen hatte) dann noch überredet um eine zusätzliche "Hands-on"-Session über jQuery im Detail zu verlängern.

Gestern, im Rahmen des 5-jährigen Jubiläums der Usergroup, durfte ich dann mit meinen beiden Vorträgen zu Gast sein und wurde sehr nett und interessiert empfangen.

Hier nun die PDFs meiner Vorträge zu Unobtrusive Javascript und jQuery.

Mein Beispiel zu dem neuen jQuery-Plugin "YAML-Tabs" ist noch unveröffentlicht, wird aber in Kürze zusammen mit der neuen YAML-Version online gehen und dann hier verlinkt werden.

Bilder des Abends gibt's natürlich bei Flickr