Ein paar einfache Schritte, um die Navigation barrierefreier zu machen

Ein neues Jahr, ein neues Blog-Projekt.  Torsten Landsiedel  hat seine Idee von regelmäßigen Blogbeiträgen wiederbelebt. Dieses Mal muss aber nicht jede Woche ein neuer Beitrag geschrieben werden, sondern es reicht ein Beitrag alle zwei Wichen aus, sowie ein Kommentar, ebenfalls alle zwei Wochen aus. Da ich schon in den vorherigen Projekten immer mit dabei war, lasse ich es mir natürlich auch dieses Mal nicht nehmen. Aber wie auch zuletzt, werde ich wieder zweisprachig bloggen. In der einen Woche in Englisch und dann in der Folgewoche mit dem gleichen Thema in Deutsch. So kommen also hoffentlich in diesem Jahr je 26 englische und deutsche Beiträge dazu.

Themenmonat Barrierefreiheit

Simon Kraft startet das neue Jahr ebenfalls mit einem kleinen Blog-Projekt. Er hat den Januar zum Themenmonat für Barrierefreiheit erklärt und alle, die Blogbeiträge, Podcasts oder Videos produzieren dazu aufgerufen, sich mit dem Thema zu beschäftigen. Unter dem Hashtag #FokusBarrierefreiheit sollen diese dann gesammelt werden. Dies ist also mein erster von zwei Beiträgen zu diesem wichtigen Thema, das mir persönlich sehr am Herzen liegt. Es werden im Laufe der Jahre aber vermutlich noch ein paar folgen.

Barrierefreie Navigationen

In diesem ersten Blogbeitrag im Jahr 2020 möchte ich euch zeigen, die ihr mit ein paar einfachen Schritten euere Website-Navigation barrierefreier machen könnt, sollte sie es nicht bereits sein. Der Fokus liegt hier vor allem auf der Bedienbarkeit mit Tastatur.

Verbessert die visuelle Barrierefreiheit

Die Navigation ist vermutlich das wichtigste Element einer jeden Website. Sowohl Menschen mit voller, als auch solche mit eingeschränkter Sehkraft finden die meisten Inhalte eurer Seite über die Navigation. Daher sollte die Navigation für alle “visuell barrierefrei” sein. Das betrifft nicht nur Menschen, sondern auch technische Hilfsmittel wie etwa sogenannte Screenreader.

Versteckt die Untermenüs nicht

Wird ein Screenreader verwendet, dann können nur solche Elemente vorgelesen werden, die auch „sichtbar“ sind. Wenn also ein Untermenü über eine CSS-Regel ausgeblendet wird, dann sind diese Menüpunkte für Menschen die Screenreader und anderen Hilfsmittel verwenden nicht sichtbar.

Versteckt sie anders

Für eine klassische horizontale Navigation wird oft eine CSS-Regel verwendet, die in etwa wie folgt aussieht (hier am Bespiel des Yoko Themes von Elmastudio):

#branding #mainnav ul ul {
	display: none;
	float: left;
	position: absolute;
	top: 2em;
	left: 0;
	z-index: 99999;
}
#branding #mainnav ul li:hover > ul {
	display: block;
}

Das Untermenü wird hier standardmäßig ausgeblendet. Bei einem “Hover” wird die display Eigenschaft dann auch block geändert, wodurch das Untermenü sichtbar wird.

Stattdessen kann man aber die Elemente einfach aus dem Viewport, dem sichtbaren Bereich, heraus verschieben, so dass die Elemente auch nicht mehr von Menschen gesehen werden können, aber weiterhin von Screenreadern:

#branding #mainnav ul ul {
	display: block;
	opacity: 1;
}
#branding #mainnav ul li:not(.focus):not(:hover) > ul {
	position: absolute;
	left: -999em !important;
	opacity: 0 !important;
}

Mit diesem Code zeigen wir Untermenüs immer an. Wir verschieben sie aus dem sichtbaren Bereich heraus und machen sie transparent – also ebenfalls “unsichtbar” – solange der Hauptpunkt nicht fokussiert ist und nicht die CSS Klasse focus hat.

Stelle einen Fokus-Style bereit

Damit eine Navigation wirklich mit der Tastatur bedient werden kann, ist es nicht nur wichtig, dass alle Menüpunkte erreicht werden können. Es muss auch visuell erkennbar sein, an welcher Stelle der Navigation man sich mit der Tastatur gerade befindet.

Leider deaktivieren sehr viele Themes global die outline Eigenschaft für alle Elemente. Man kann nun also zur Lösung entweder die outline wiederherstellen oder aber den focus Zustand genau so stylen wie den hover Zustand. Für das Yoko Theme würde das wie folgt aussehen:

#branding #mainnav ul li a:focus,
#branding #mainnav ul li a.focus {
	background:#F0F0F0;
	color: #999;
}

Wir setzen hier den Style sowohl für den focus Zustand, als auch für Elemente mit der Klasse focus, was uns im zweiten Schritt helfen wird.

Verbesserung der Barrierefreiheit bei Benutzung der Tastatur

In den meisten Navigationen wird der hover Zustand verwendet, um ein Untermenü einzublenden. Wenn man sich aber mit der Tastatur durch die Seite navigiert, dann wird dieser Zustand nicht aktiviert und CSS-Regel werden nicht aktiv. Um die Navigation also besser benutzbar zu machen, verwenden wir ein wenig JavaScript, um eine CSS-Klasse focus hinzuzufügen, wenn/solange ein Hauptmenüpunkt oder ein Untermenüpunkt fokussiert ist:

( function() {
	var container, menu, links, i, len;
	var navigationContainerId = 'mainnav';
	var menuItemFocusedClass  = 'focus';

	container = document.getElementById( navigationContainerId );
	if ( ! container ) {
		return;
	}

	menu = container.getElementsByTagName( 'ul' )[0];

	if ( -1 === menu.className.indexOf( 'nav-menu' ) ) {
		menu.className += ' nav-menu';
	}

	// Get all the link elements within the menu.
	links = menu.getElementsByTagName( 'a' );

	// Each time a menu link is focused or blurred, toggle focus.
	for ( i = 0, len = links.length; i < len; i++ ) {
		links[i].addEventListener( 'focus', toggleFocus, true );
		links[i].addEventListener( 'blur', toggleFocus, true );
	}

	/**
	 * Sets or removes .focus class on an element.
	 */
	function toggleFocus() {
		var self = this;

		// Move up through the ancestors of the current link until we hit .nav-menu.
		while ( -1 === self.className.indexOf( 'nav-menu' ) ) {

			// On li elements toggle the class .focus.
			if ( 'li' === self.tagName.toLowerCase() ) {
				if ( -1 !== self.className.indexOf( 'focus' ) ) {
					self.className = self.className.replace( ' focus', '' );
				} else {
					self.className += ' focus';
				}
			}

			self = self.parentElement;
		}
	}
} )();

Wenn ihr dieses Snippet einsetzt, könnt ihr einfach das id Attribut des Containers der Navigation und die CSS-Klasse, die ein fokussiertes Element bekommen soll, in den Zeilen 3 und 4 eintragen. Das Snippet kommt auch ganz ohne Bibliotheken wie jQuery aus und sollte in jedem Theme funktionieren, das die normale WordPress Navigation und keine zusätzlichen JavaScript-Optimierungen für die Navigation verwendet. Es handelt sich bei dem Snippet um eine geringfügig an Version des _s Themes.

Wenn ihr diesen Snippet zu eurer Seite hinzufügt, kann durch alle Haupt- und alle Untermenüpunkte unter Verwendung der Tab-Taste vorwärts und rückwärts navigiert werden.

Bonus: Verbesserung der Benutzerbarkeit auf Tablets

Ein weiteres typisches Problem beim Einsatz des hover Zustands in einer horizontalen Navigation ist der Umstand, dass es einen solchen auf mobilen Geräten wie etwa Tablets nicht gibt. Klickt man also auf einen Hautptmenüpunkt, wird kurzzeitig das Untermenü sichtbar, die Seite wird aber sofort auf den angeklickten Hauptmenüpunkt wechseln.

Wir möchten aber, dass beim ersten Klick auf den Menüpunkt das Untermenü sichtbar wird und erst beim zweiten Klick der Link unter dem Hauptmenüpunkt aufgerufen wird. Hat ein Hauptmenüpunkt keine Untermenüpunkte, dann soll bereits der erste Klick zu der entsprechenden Seite führen. Das kann mit folgendem zusätzlichen Snippet erreicht werden:

( function() {
	var container;
	var navigationContainerId = 'mainnav';
	var menuItemFocusedClass  = 'focus';


	container = document.getElementById( navigationContainerId );
	if ( ! container ) {
		return;
	}

	( function( container ) {
		var touchStartFn, i,
			parentLink = container.querySelectorAll( '.menu-item-has-children > a, .page_item_has_children > a' );

		if ( 'ontouchstart' in window ) {
			touchStartFn = function( e ) {
				var menuItem = this.parentNode, i;

				if ( ! menuItem.classList.contains( menuItemFocusedClass ) ) {
					e.preventDefault();
					var menuItemLength = menuItem.parentNode.children.length;
					for ( i = 0; i < menuItemLength; ++i ) {
						if ( menuItem === menuItem.parentNode.children[i] ) {
							continue;
						}
						menuItem.parentNode.children[i].classList.remove( menuItemFocusedClass );
					}
					menuItem.classList.add( menuItemFocusedClass );
				} else {
					menuItem.classList.remove( menuItemFocusedClass );
				}
			};

			var parentLinkLength = parentLink.length;
			for ( i = 0; i < parentLinkLength; ++i ) {
				parentLink[i].addEventListener( 'touchstart', touchStartFn, false );
			}
		}
	}( container ) );
} )();

Das Snippet reagiert auf das ontouchstart Event und stellt die notwendigen Anpassungen für eine Drop-Down-Navigation auf mobilen Endgeräten bereit.

Fazit

Es ist nicht wirklich schwer eine Navigation barrierefrei zu machen. Man muss lediglich ein wenig das CSS anpassen und etwas JavaScript verwenden. Am besten setzt man das Ganze in einem Child-Theme um. Man kann die Anpassungen aber auch als Verbesserung am Originaltheme melden, damit alle, die das Theme einsetzen, davon profitieren. Für das Yoko Theme habe ich die Lösung mal als Plugin zusammengefasst, das alle Verbesserungen enthält. Versucht es doch mal selbst! Installiert euch das Yoko Theme und versucht auf der Seite nur mit dem Keyboard zu navigieren. Installiert und aktiviert dann das Plugin und versucht es erneut. Testet ebenfalls mal die Navigation mit einem Tablet, indem ihr die Geräte-Emulation eures Browsers verwendet.

Im Anschluss solltet ihr mal euer eigenes Theme testen. Ist es bereits barrierefrei? Falls nicht, könnt ihr es mit den hier vorgestellten Techniken einfach barrierefreier machen? Sollte euer Theme ein sogenanntes “Hamburg-Menü” verwenden, dann schaut euch mal den gesamten Code des _s Themes an, das ein solches Menü mit Untermenüs sehr gut bedienbar und barrierefrei umsetzt.

Veröffentlicht von

Bernhard ist fest angestellter Webentwickler, entwickelt in seiner Freizeit Plugin, schreibt in seinem Blog über WordPress und andere Themen, treibt sich gerne bei den WP Meetups in Berlin und Potsdam herum und läuft nach Feierabend den ein oder anderen Halbmarathon.

6 Kommentare » Schreibe einen Kommentar

  1. Hi Bernhard,

    danke für den Artikel! Dropdown-Navis, die sich nur mit der Maus anständig bedienen lassen, sieht man in der Tat leider noch viel zu oft …

    Ein paar Gedanken/Fragen:

    Wenn die Unterpunkte nur aus dem sichtbaren Bereich verschoben werden, aber nicht richtig versteckt, dann haben zumindest Tastatur-User glaube ich keine Chance, ein Untermenü auszulassen, oder (eventuell trifft dasselbe auf Screenreader zu, aber vielleicht gibt es da auch einen Shortcut, um das zu umgehen)?

    Sprich: die müssen dann alle Untermenüpunkte durchtabben, um beispielsweise zum letzten Menüpunkt zu gelangen, was ich mir etwas nervig vorstelle (oder sehr nervig, wenn viele Untermenüpunkte da sind).

    Wäre es da eventuell besser, bei jedem Obermenüpunkt dahinter einen Button einzubauen, der das Untermenü öffnet?

    Und bei der Lösung für Touch frage ich mich, wie man deutlich macht, dass man zweimal drücken muss, damit sich die Seite des Oberpunktes öffnet. Der User könnte ja auch denken, dass das nur ein Platzhalter-Menüpunkt ist, der keine eigene Seite hat.

    Soweit erst mal an Gedanken dazu 🙂

    Viele Grüße
    Florian

    • Danke für deine Anregungen Florian. Es ist natürlich richtig, dass man mit der Tastatur durch alle Punkte navigieren muss. Aber es geht ja gerade darum, dass es ohne diesen Patch gar nicht an geht. Untermenüpunkte wären sonst nicht erreichbar. In guten Themes gibt es aber oft als erstes einen sogenannten “Skip link”, mit dem man direkt zum Inhalt springen kann. Man muss also nicht immer durch die gesamte Navigation durch, um zum Inhalt zu kommen.

      Die Variante mit den Buttons könnte man auch umsetzen, man muss diese dann nur entsprechend Stylen. Wenn man also beispielsweise ohnehin einen “Pfeil nach unten” neben Menüpunkten haben möchte, kann man diesen als Button einrichten. Genau das macht auch das JavaScript aus _s für alle Menüpunkte. Es wäre auch ein gutes visuelles Feedback für alle, dass es überhaupt Untermenüpunkte gibt.

      Das mit der Touch-Bedienung ist auch bei Desktop-Auslösung ein Problem. Sehr häufig stellt man sich bei Top-Navigationen die Frage, wohin der Hauptpunkt verlinkt und ob man diesen nochmal zusätzlich als Unterpunkt mit gleichem Ziel haben sollte, da einige den Punkt selbst nicht immer als eigenen Link wahrnehmen.

  2. Hallo Bernhard,

    du schreibst: “Sehr häufig stellt man sich bei Top-Navigationen die Frage, wohin der Hauptpunkt verlinkt und ob man diesen nochmal zusätzlich als Unterpunkt mit gleichem Ziel haben sollte, da einige den Punkt selbst nicht immer als eigenen Link wahrnehmen.”
    Genau darin besteht mein Problem. Das Hauptmenü enthält Punkte mit und ohne Unterpunkte, aber auch die Menüpunkte, die Unterpunkte und einen Button haben, der das anzeigt, sind selbst zu eigenen Seiten verlinkt. Das als Unterpunkt noch einmal aufzulisten, irritiert aber m.E. auch.
    Gibt es dafür eine “vernünftige” Lösung?

    Viele Grüße
    Wolfgang

    • Hallo Wolfgang,

      eine optimale Lösung gibt es hier wohl nicht, da jede Website ein wenig anders ist. Meine Empfehlung ist hier meistens, dass solche Seiten zwar selbst in der Navigation verlinkt sein sollten, sie selbst aber keinen großen “alleinigen” Wert haben. Es sollte also eine Seite sein, die alle darunter einsortierten Seiten kurz erwähnt. Im einfachsten Fall ist es eine schmucklose Linkliste oder eben eine kleine “Landingpage” mit ein paar Anzeißertexten und dem Link zur Unterseite.

  3. Diese Navigationen mit Untermenüs sind tatsächlich sehr trickreich, und es gibt keine Lösung, die für alle greift. Der Button zum Ausklappen von Untermenüpunkten ist häufig die sicherste Lösung. Und wenn der Hauptmenüpunkt selbst tatsächlich nirgendwohin verlinken soll, wäre dieser als reiner Text, vielleicht etwas ansprechender per CSS gestaltet, gar nicht schlecht. Oder eben die von Bernhard vorgeschlagene Methode einer einfachen Landing-Seite, die die Untermenüpunkte per Anreißer vorstellt.

  4. Ich tausche den Code von _s bei Menüs mit den klassichen “Hover-Untermenüs” inzwischen so aus, dass bei nach allen Obermenüpunkten automatisch ein visuell unsichtbarer Button eingefügt wird, der beim focus sichtbar wird, und mit dem auf Wunsch das Untermenü ausgeklappt werden kann. aria-expanded muss dan bei diesem Button umgeschaltet werden, nicht beim Obermenüpunkt. Außerdem füge ich noch aria-current hinzu, um den aktuellen Link zu markieren. Kann bei Interesse hier in Aktion angeschaut werden: https://changing-cities.org/

    Und vielleicht hilft dieser Code jemand, ich hab leider noch keinen so schönen Blog wie Bernhard, aber irgendwann wäre das mal ein Thema für einen Beitrag. (Der JS-Code kann auf der Seite angeschaut werden: https://changing-cities.org/wp-content/themes/changing_cities/js/navigation.js)

    function add_aria_current_to_nav_link( $atts, $item, $args ) {
    
    	if ( $item->current ) {
    		//https://www.w3.org/WAI/tutorials/menus/structure/#using-wai-aria
    		$atts["aria-current"] = "page";
    	}
    
    	return $atts;
    }
    
    add_filter( 'nav_menu_link_attributes', 'add_aria_current_to_nav_link', 10, 3 );
    
    
    function add_extend_button_after_parent_nav_link( $args, $item, $depth ) {
    
    	// https://www.w3.org/WAI/tutorials/menus/flyout/#flyoutnavkbfixed
    	if ( $item->has_children ) {
    		$args->after = get_submenu_toggle_button( $item );
    	} else {
    		$args->after = "";
    	}
    
    	return $args;
    }
    
    add_filter( 'nav_menu_item_args', 'add_extend_button_after_parent_nav_link', 10, 3 );
    
    /**
     *
     * https://www.w3.org/WAI/tutorials/menus/flyout/#flyoutnavkbfixed
     * But add expanded to button, not to top level link:
     * https://www.smashingmagazine.com/2017/11/building-accessible-menu-systems/
     *
     * @param WP_POST $item
     *
     * @return string
     */
    function get_submenu_toggle_button( WP_POST $item ): string {
    
    	$label_template = _x( "%s Untermenü", "Menu Toggle Button", THEME_DOMAIN );
    
    	$label = sprintf( "$label_template", $item->title );
    
    	$html = sprintf( "%s",
    		$item->ID,
    		$label,
    		"path to icon or inline svg"
    	);
    
    	return $html;
    
    }
    
    
    /**
     * Since WP nav items lack the information if they have children, we add this
     * property manually.
     *
     * @param $items
     *
     * @return mixed
     */
    function add_has_children_property_to_nav_items( $items ) {
    	$parents = wp_list_pluck( $items, 'menu_item_parent' );
    
    	foreach ( $items as $item ) {
    		$item->has_children = in_array( $item->ID, $parents );
    	}
    
    	return $items;
    }
    
    add_filter( 'wp_nav_menu_objects', 'add_has_children_property_to_nav_items' );
    

Schreibe einen Kommentar

Pflichtfelder sind mit * markiert.