Navigation
Navigation is the way users find and traverse the different pages available on your site. For this reason, it is imperative that navigation is accessible. By their nature, links are tab-able and all keyboard users and screen readers will read them–so, if your navigation is coded with links, a screen reader should find them.
Navigation becomes more complicated when we move to tablet and mobile views. With the general practice these days being that we condense all navigation to be hidden behind a “menu” icon, we need users to be able to understand what that menu icon’s purpose is, and what to expect upon clicking on it.
Best Practices
Horizontal, Desktop Navigation
Code your navigation using link tags.
Put your links within an unordered list structure so that a screen reader will read out how many things are in the list to give visually impaired users the most information possible about the contents of the navigation.
Use the semantic
<nav>
tag around your unordered list and links with an ARIArole='navigation'
attribute.- Testing this navigation with Chrome Vox, we found that without an ARIA
role
attribute, the screen reader would not read any other aria attributes–for this reason, it seems ARIA roles are crucial for screen readers.
- Testing this navigation with Chrome Vox, we found that without an ARIA
Optionally, attach an
aria-label
attribute to your navigation to give users of assistive technology as much information as possible (especially if there are multiple navigations on your site).- Perkins School for the Blind website, for example, has three sets of navigation and uses an
aria-label
androle='navigation'
for each (the ARIA labels are: ‘Utility Navigation,’ 'Accessibility Navigation,’ and 'Main Navigation’).
- Perkins School for the Blind website, for example, has three sets of navigation and uses an
1 2 3 4 5 6 7 8 9 | <nav class="primary-nav primary-nav--narrow"> <ul> <li><a href="/our-work/">Our work</a></li> <li><a href="/articles/">Articles</a></li> <li><a href="/about/">About us</a></li> <li><a href="/events/">Events</a></li> <li class="primary-nav__active"><a href="/contact/">Contact<span class="visuallyhidden"> (current section)</span></a></li> </ul> </nav> |
Mobile Navigation
Mobile navigation often acts in very similar ways to accordions on websites. For further information, you can also look to the accordion section.
Mobile Trigger, Hamburger Button
- Use a
button
tag for your mobile navigation trigger; if you must use another HTML element, ensure that you use the ARIA attributerole='button'
so screen readers will know it is clickable. - If your button has only an image, icon, or vague link text, put an
aria-label
on your trigger/hamburger. (Keep in mind that if you use anaria-label
, a screen reader will only read the label and not the button text most times). - For example, you can have:
aria-label='Mobile Navigation Trigger'
or 'Open Menu.’ - Additionally, if you really want to be specific, you can toggle your button’s text between 'Open Menu’ and 'Close Menu’ with JavaScript.
- Add and toggle an
aria-expanded
attribute to your button letting the user know if the content the button controls are expanded or not.
1 2 3 4 5 6 7 | <section class="other-mobile-navigation"> <button aria-expanded="false" class="other-trigger" aria-label="Mobile Navigation Button"> <span class='icon-menu'></span> <span class="other-trigger-status screenreader-text closed">Open</span> Menu </button> </section> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | var $otherTrigger = $('.other-trigger'), $otherTriggerWord = $('.other-trigger-status'), $otherMenu = $('.other-primary-navigation'); function toggleOtherTriggerClass() { if (!$otherTrigger.hasClass('is-active')) { $otherTrigger.addClass('is-active'); $otherTrigger.attr("aria-expanded","true"); } else { $otherTrigger.removeClass('is-active'); $otherTrigger.attr("aria-expanded","false"); } }; function toggleOtherTriggerWord() { if ($otherTriggerWord.hasClass('closed')) { $otherTriggerWord.removeClass('closed'); $otherTriggerWord.addClass('open'); $otherTriggerWord.html('Close'); } else { $otherTriggerWord.removeClass('open'); $otherTriggerWord.addClass('closed'); $otherTriggerWord.html('Open'); } }; function toggleOtherMenuClass() { if (!$otherMenu.hasClass('is-visible')) { $otherMenu.addClass('is-visible'); $otherMenu.focus(); } else { $otherMenu.removeClass('is-visible'); } }; function toggleOtherMenu() { $otherTrigger.on("click", function(e){ toggleOtherTriggerClass(); toggleOtherMenuClass(); toggleOtherTriggerWord(); $otherMenu.slideToggle("fast"); }); }; function resetOtherMenu() { if (!$otherMenu.hasClass('is-visible')) { $otherMenu.removeAttr('style'); } else { $otherMenu.removeClass('is-visible').removeAttr('style'); } }; function resetOtherMenuTrigger() { if (!$otherTrigger.hasClass('is-active')) { return } else { $otherTrigger.removeClass('is-active'); } }; //call this function on page load $(document).ready(function(){ toggleOtherMenu(); }); |
Navigation List (generally hidden)
- This should follow all of the characteristics of the horizontal menu specified above, including that is has a semantic
nav
tag wrapping a list of links with arole='navigation'
attribute, and uses anaria-label
to describe its purpose. - If you have your navigation hidden on mobile views, use:
{display: none;}
so that screen readers can not read it (if you use{visibility: hidden;}
, screen readers can still sometimes read that). - Additionally, you can use an ARIA
aria-hidden='true'
attribute to ensure screen readers will not be reading your hidden content, though this is often unnecessary if you are using{display: none;}
*. - If using an
aria-hidden
attribute, you should toggle this property upon showing and hiding the navigation.
1 2 3 4 5 6 7 8 | <nav aria-label="Mobile Accessibility Navigation Dropdown" class="primary-navigation" role="navigation"> <ul class="navigation-item-group"> <li class="nav-item"><a href="/">Semantic HTML</a></li> <li class="nav-item"><a href="/aria">ARIA</a></li> <li class="nav-item"><a href="/font">Font & Font Size</a></li> <li class="nav-item"><a href="/color">Contrast & Color</a></li> </ul> </nav> |
Live Example
Tools & Resources
Other Live Examples of Accessible Horizontal and Mobile Navigation
* For navigation that moves to mobile navigation, with perhaps a display: none;
nav list, it is actually not commonly accepted to use aria-hidden
attributes anymore. We asked someone in the a11y slack room, and they told us that “if you’re already [applying display: none;
] to elements, you generally won’t need [aria-hidden
] anyway.”