Museum/Eine zugängliche Multilevel-Dropdown-Navigation

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Achtung!

Dieser Artikel entspricht nicht mehr der best practice. Er sollte nicht für die Umsetzung aktueller Projekte eingesetzt werden.

Eine neue und aktuelle Version dieses Artikels finden sie unter: Navigation/Dropdown-Menü --Matthias Scharwies (Diskussion) 08:46, 2. Dez. 2015 (CET)

Unter Dropdown-Menus versteht man Menus, die sich durch Userinteraktion erweitern. Man findet sie vor allem bei größeren Webangeboten oder Webshops. Während dieser Artikel vor allem ein horizontales Navigations-Menu bespricht, lassen sich die Codes aber leicht auch für andere Darstellungen anpassen.

Bei Dropdown-Menus wird die Keyboard-Steuerung meist vernachlässigt. Sobald aber CSS aktiviert ist, wird eine ganze Gruppe von Menschen vernachlässigt: Leute mit Sichtbehinderungen und Leute, welche die Maus nicht bedienen können. Die fehlende Implementierung von Keyboardsteuerung für Dropdown-Menus ist typisch, da für den Laien nicht ohne weiteres machbar. Accessibility-Puristen vermeiden deshalb solche Menus. Doch das muss nicht so bleiben, denn die hiesige Steuerung funktioniert doch recht gut. Sie darf als akzeptable Zwischenlösung gelten, bis mit dem CSS die neuen Eigenschaften für die Navigation implementiert werden.

Die vorliegende Lösung restauriert die für normale Linklisten verfügbare Funktionalität der TAB-Taste. Sie restauriert damit ein Stück Konvention oder Erwartung. Sie möchte allerdings keinen Freibrief für wild verschachtelte Menulisten schreiben. Auch wenn hier eine Tastaturlösung vorliegt, sollte man dem Mausbenutzer nie mehr als zwei Klapplevel abverlangen.

Leistung und Beschränkungen

  • Beliebig viele Unterlevel. Aus Usability-Gründen sollte man sparsam mit Levels umgehen. Ab dem zweiten Level beansprucht jeder Level weiteren horizontalen Platz. Dieser steht aber nicht unbedingt zur Verfügung.
  • Tastatur-Unterstützung für Keyboard (TAB-Taste) bis drei Sublevel.
  • Markup für das aktuelle Document und den Pfad zum aktuellen Document.
  • Individuelle Klassen für jeden Level. für flexibleres Styling
  • Unterstützung für Browser, welche :hover nicht auf alle Elemente anwenden

Der Stand der Dinge (Browser-Support)

Beachten Sie weitere Meldungen auf der [[Artikel_Diskussion:Eine_zugängliche_Multilevel-Dropdown-Navigation|Diskussionsseite]].

  • FX 3.5 OK
  • Opera 9.5 OK
  • Opera 11 OK (shift Arrow-Keys statt Tab)
  • MSIE 8: OK, keine Pfeilsymbole

Das Ziel dieses Projekts ist nicht, die Tastaturführung und Kompatibilität für alle Browser zu erreichen, sondern damit das effektiv grösste Segment abzudecken. Menschen mit betreffenden Schwächen besorgen sich aus eigenem Interesse oft einen geeigneten modernen Browser.

HTML

Beispiel


<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Eine zugängliche Multilevel-Dropdown-Menu</title>
<link type="stylesheet">
<style id="style">
</style>
</head>
<body>
<h1>Demo Multilevel-Dropdown-Menu</h1>

<ul id="nav">
   <li><a>Menu 1</a>
       <ul class="level1">
           <li><a>Menu 1.1</a>
               <ul class="level2">
                   <li><a href="">Menu 1.1.1</a></li>
                   <li><a href="">Menu 1.1.2</a></li>
                   <li><a href="">Menu 1.1.3</a></li>
               </ul>
           </li>
           <li><a>Menu 1.2</a>
               <ul class="level2">
                   <li><a href="">Menu 1.2.1</a></li>
                   <li><a href="">Menu 1.2.2</a></li>
                   <li><a href="">Menu 1.2.3</a></li>
               </ul>
           </li>
       </ul>
   </li>
   <li><a class="current dir">Menu 2</a>
       <ul class="level1">
           <li><a href="">Menu 2.1</a></li>
           <li><a class="current dir">Menu 2.2</a>
               <ul class="level2">
                   <li><a>Menu 2.2.1</a>
                       <ul class="level3">
                           <li><a href="">Menu 2.2.1.1</a></li>
                           <li><a href="">Menu 2.2.1.2</a></li>
                           <li><a href="">Menu 2.2.1.3</a></li>
                       </ul>
                   </li>
                   <li><a class="current page">Menu 2.2.2</a></li>
               </ul>
           </li>
       </ul>
   </li>
   <li><a href="">Menu 4</a></li>
   <li><a href="">Menu 5</a></li>
</ul>
<script src="your_js_lib_name.js" type="text/javascript"></script>
</body>
</html>


Zum Code

  • Verwenden Sie in jedem li-Element ein a-Element ohne href-Attribut, wenn es sich um ein Label handelt. Da das eingesetzte Javascript nach diesem a-Element sucht, haben sie für einmal keine Alternative.
  • Für das aktuell angezeigte Doc schreiben Sie die Klasse "current page" in das a-element.
  • Für Labels, die im Pfad zum aktuell angezeigte Doc liegen, schreiben Sie die Klasse "current dir" in das a-element.

CSS

Das CSS ist kommentiert.

Beispiel


Erst abweichende Elemente normalisieren
#nav, #nav ul, #nav li {
   display:block; 
   margin:0; 
   padding:0; 
   list-style:none; 
}
Generelle vererbbare Eigenschaften innerhalb des Menus
#nav, #nav * { 
   font-size:14px;
   line-height:20px;
   color:#000;
   background:#fff;
   text-align:left;
}
Alle Labels (a ohne href Attr) und Links haben ein bestimmtes uniformes Aussehen. Wir müssen hierbei fixes für den MSIE 7 -- anwenden, da diese definierte Breiten brauchen.
#nav a{
   display:block;
   background:#fff;
   padding: 0 5px 0 10px;
}

  * html #nav li a { width:6em; }  /* Fix für MSIE 6 ? */
  * html #nav ul a { width: 9em;}  /* Fix für MSIE 6 ? */
  *:first-child+html #nav a { width:6em; }     /* Fix für MSIE 7 */
  *:first-child+html #nav ul a { width: 9em;}  /* Fix für MSIE 7 */
alle aktivierbaren Links haben bestimmte Farben
#nav a[href] { 
   text-decoration:none;
   color:#f00;
}
Die immer sichtbare Menu-Items.

Für den Border brauchen wir wieder Hacks.

Ältere Browser kennen kein box-shadow. Sie brauchen deshalb eine sichtbare Randfarbe.
#nav > li {
   display:inline;
   display:inline-block; 
   vertical-align:top;    
   border:1px solid #ccc;
}

/* MSIE8 -- verstehen die Farbe transparent nicht */
:root #nav > li {
   border:1px solid transparent; 
}

  * html #nav li    
         { float:left; zoom:1; border: 1px solid #ccc; } /* MSIE 6 fix ?? */
  * html #nav ul li 
         { float:none; display:block } /* MSIE 6 fix ?? */
  *:first-child+html #nav > li 
         { display:inline; border: 1px solid #ccc; } /* MSIE 7 fix*/
Die Focus-Linie verbergen, sie wird durch passenden Hintergrund kompensiert.
#nav *:focus { 
   outline-width:0; 
}
Die eigentliche Menu-Gestaltung:
#nav {
   text-align:center;
   box-shadow:0px 6px 10px -5px #666, inset 0px -8px 8px -7px #000, inset 0px 4px 8px -7px #666;  /* Schatteneffekte */
}
#nav > li > a {
   padding: 5px 10px;
   box-shadow:inset 0px -8px 8px -7px #444, inset 0px 4px 8px -7px #666;
}
Alle Levels erhalten ein einheitliches Bild.

Wir werden mit Positionierung arbeiten, nicht mit display:none.

Wir haben dabei die maximale Zugänglichkeit für Screenreader im Sinn.
/* Jeder Level wird absolut positioniert und hat eine definierte Mindestbreite.
*/
#nav ul {
   position:absolute;
   min-width:10em;
   border:1px solid #ccc;
   text-align:left;
   box-shadow:3px 5px 10px #666;
}

/* Jedes Item in jedem Level erzeugt einen neuen Koordinatenkontext */
#nav li {
   position:relative;
} 

/* Der 1. Level erscheint vertikal unter den Menu-Labels */
#nav .level1 {
   top:30px;
   left: -1999px;    /* einblenden left:-1px;*/
}

/* Der 2. bis x. Level erscheint horizontal versetzt neben dem ersten Level */
#nav .level2, #nav .level3, #nav .level4 {
   top:-1px;
   left:-1999px;     /*einblenden left:8em;*/
}
Den Menupfad durch die verschiedenen Level zur aktuellen Seite hervorheben.
#nav a.current{ 
   background: #aaf; 
}
Betone die im moment gehoverten Items. Hier restaurieren wir die weiter oben deaktivierte Fokus-Linie. Wir setzen Sie aber auf ein anderes Element und gestalten sie auffälliger als dies etwa beim Firefox standardmässig der Fall ist.
#nav a:hover, #nav li.hover >  a { 
   background: #ddd; 
   outline:1px solid #f90;
   outline-width:2px;
   outline-offset:2px;
   position:relative;
   z-index:20;
}
#nav a.current:hover, #nav li.hover >  a.current{
   background: #aaf; 
}
Gebe den Labels, die keine Links sind, Dropdown/right-Pfeil. Leider werden ältere Browser dies nicht umsetzen.
#nav ul a:not([href]):not([class="current page"]):before { 
   float:right;  
   content: "\25b8";  /* Pfeil rechts */
   padding-left:5px; 
}
#nav > li > a:not([href]):not([class="current page"]):before { 
   float:right; 
   content: "\25be";  /* Pfeil runter */
   padding-left:5px; 
}
Wir korrigieren die z-index-Werte.
.level1 { z-index:11; }
.level2 { z-index:12; }
.level3 { z-index:13; }
.level4 { z-index:14; }
Wir gestalten das Interaktives Einblenden.

Hierbei werden lediglich die Positionen korrigiert.

Für moderne Browser bietet es sich an, dieses Einblenden mit einer kleinen Verzögerung im sichtbaren Haupt-Level zu gestalten.
#nav > li:hover .level1, #nav > li.hover .level1           { 
   left:-1px; 
   /* den obersten Level verzögert einblenden */
   transition-property: left;  
   transition-delay: 0.3s; 
}
#nav li:hover > .level2, #nav .level1 >li.hover .level2  { left:10em; }
#nav li:hover > .level3, #nav .level2 >li.hover .level3  { left:10em; }
#nav li:hover > .level4, #nav .level3 >li.hover .level4  { left:10em; }


Javascript

Das Script soll die hover-Klasse für Maus und TAB-Taste (Focus) erzeugen. Es erzeugt auch für jedes a-Element ein tabindex-Attribut.

Sie können beim Aufruf der Funktion zwei Parameter übergeben:

  • die Id der Navigation
  • Einen numerischen Wert, welchen einen konstanten Tabindex-Wert erzeugt.

Binden Sie das Javascript als letztes im body des HTML ein.

Beispiel


function addUsabilityToMenu(id, tabindex){
   var items = document.getElementById(id).getElementsByTagName("a");

   for( var i=0; i < items.length; i++ ){
      items[i].tabIndex = tabindex;
      items[i].onmouseover = function(){
         this.parentNode.className = "hover";
      };
      items[i].onmouseout = function(){
         this.parentNode.className = "";
      };
      items[i].onfocus = function(){
         this.parentNode.className = "hover";
         if(this.parentNode.parentNode.parentNode.nodeName=="LI"){
            this.parentNode.parentNode.parentNode.className="hover";
            if(this.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="LI"){
               this.parentNode.parentNode.parentNode.parentNode.parentNode.className="hover";
               if(this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="LI"){
                  this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.className="hover";
               }
            }
         }
      };
      items[i].onblur = function(){
         this.parentNode.className = "";
         if(this.parentNode.parentNode.parentNode.nodeName=="LI"){
            this.parentNode.parentNode.parentNode.className="";
            if(this.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="LI"){
               this.parentNode.parentNode.parentNode.parentNode.parentNode.className="";
               if(this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.nodeName=="LI"){
                  this.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.className="";
               }
            }
         }
      };
   }
}

addUsabilityToMenu("nav", 1);


Live-Beispiel

Das vorliegende Beispiel, mit etwas mehr Markup können Sie hier betrachten und testen.

Dropdown-Menu für Tasten ansehen …
... (siehe Link oben rechts) ...