Building the main navigation for a website
There are many different ways of building the main navigation of a website, in terms of styling, functionality, and the underlying markup and semantic information. If the implementation is too minimalist, it works for most people, but the user experience (UX) might not be great.
If it's over-engineered, it might confuse users or even hinder them from being able to access it at all.
For most websites, you want to build something that's neither too simple, nor too complicated.
Building layer by layer
In this tutorial you start with a basic setup and add features layer by layer up to a point where you provide just enough information, styling, and functionality to please most users. To achieve that you make use of the progressive enhancement principle, which states that you start with the most fundamental and robust solution and progressively add layers of functionality. If one layer fails to work for some reason, the navigation will still work because it gracefully falls back to the underlying layer.
Basic structure
For a basic navigation you need two things:
elements and a few lines of CSS to improve the default styling and layout of your links.
HomeAbout usPricingContact
/* Define variables for your colors */
:root {
--color-shades-dark: rgb(25, 25, 25);
}
/* Use the alternative box model
Details: */
*{
box-sizing: border-box;
}
/* Basic font styling */
body {
font-family: Segoe UI, system-ui, -apple-system, sans-serif;
font-size: 1.6rem;
}
/* Link styling */
a {
--text-color: var(--color-shades-dark);
border-block-end: 3px solid var(--border-color, transparent);
color: var(--text-color);
display: inline-block;
margin-block-end: 0.5rem; /* See note at the bottom of this chapter */
margin-inline-end: 0.5rem;
padding: 0.1rem;
text-decoration: none;
}
/* Change the border-color on :hover and :focus */
a:where(:hover, :focus) {
--border-color: var(--text-color);
}
https://codepen.io/web-dot-dev/pen/wvjvJrw
View Step 1: Basic HTML and CSS" on CodePen.
This works well for most users, no matter how they're accessing the site. The navigation is accessible with a mouse, a keyboard, a touch device, or a screen reader, but there's room for improvement. You can enhance the experience by extending this basic pattern with additional functionality and information.
Here's what you can do:
Highlight the active page.
Announce the number of items to screen reader users.
Add a landmark and allow screen reader users to access the navigation directly using a shortcut.
Hide the navigation on narrow viewports.
Improve focus styling.
margin-inline-end and
margin-block-end are known as logical properties and an alternative to writing
margin-right and
margin-bottom. Logical properties are a new way of working with directions and dimensions, one that allows you to control layout through logical, rather than physical mappings. This is especially useful, if you're dealing with websites that are presented in different languages and writing modes, like right-to-left. Have a look at "Physical vs. logical properties" on CodePen for an example.
Highlight the active page
To highlight the active page, you can add a class to the corresponding link.
About us
The issue with this approach is that it conveys the information which link is active purely visually. A blind screen reader user couldn't tell the difference between the active page and other pages. Fortunately, the Accessible Rich Internet Applications (ARIA) standard offers a way to communicate this information semantically, as well. Use the aria-current="page" attribute and value instead of a class.
aria-current (state) indicates the element that represents the current item within a container or set of related elements.
A page token used to indicate a link within a set of pagination links, where the link is visually styled to represent the currently-displayed page.
Accessible Rich Internet Applications (WAI-ARIA) 1.1
With the additional attribute, a screen reader now announces something like "current page, link, About Us" instead of just "link, About Us".
About us
A convenient side effect is that you can use the attribute to select the active link in CSS, making the
active-page class obsolete.
HomeAbout usPricingContact
/* Change border-color and color for the active page */
[aria-current="page"] {
--border-color: var(--color-highlight);
--text-color: var(--color-highlight);
}
https://codepen.io/web-dot-dev/pen/OJZJpOe
View Step 2: Highlight the active page on CodePen.
Announce the number of items
By looking at the navigation, sighted users can tell that it only contains four links. A blind screen reader user can't obtain this information as quickly. They may have to work their way through the whole list of links. This might not be an issue if the list is short like in this example, but if it contains 40 links this task can be cumbersome. If a screen reader user knows upfront that the navigation contains a lot of links, they might decide to use a different, more efficient way of navigation, like the site search.
A nice way of communicating the number of items upfront, is wrapping each link in a list item (
When a screen reader user finds the list, their software will announce something like "list, 4 items".
Here's a demo of the navigation used with the screen reader NVDA on Windows.
Now you have to adapt the styling to make it look like before.
/* Remove the default list styling and create a flexible layout for the list */
ul {
display: flex;
flex-wrap: wrap;
gap: 1rem;
list-style: none;
margin: 0;
padding: 0;
}
/* Basic link styling */
a {
--text-color: var(--color-shades-dark);
border-block-end: 3px solid var(--border-color, transparent);
color: var(--text-color);
padding: 0.1rem;
text-decoration: none;
}
Using lists can have many advantages for screen reader users:
They can get the total number of items before they interact with the items.
They may use shortcuts to jump from list item to list item.
They may use shortcuts to jump from list to list.
The screen reader may announce the index of the current item (for example, "list item, two of four").
On top of that, if the page is presented without CSS, the list shows the links as a coherent group of items instead of just a pile of links.
A notable detail about VoiceOver in Safari is that you lose all these advantages, when you set
list-style: none. This is by design. The WebKit team decided to remove list semantics, when a list doesn't look like a list. Depending on the complexity of your navigation, this may or may not be an issue. On one hand, the navigation is still usable and it only affects VoiceOver in Safari. VoiceOver with Chrome or Firefox still announces the number of items, as well as other screen readers, like NVDA. On the other hand, the semantic information could be really useful in some situations. To make that decision, you should test the navigation with actual screen reader users and get their feedback. If you decide that you need VoiceOver in Safari to behave like all the other screen readers, you can work around the issue by setting the ARIA list role explicitly on the
. This reverts the behaviour to the state before you've removed the list styling. Visually, the list still looks the same.
If you validate your HTML and the validation service reports a warning like "The list role is unnecessary for element ul", you can safely ignore that.
https://codepen.io/web-dot-dev/pen/bGMGqxd
View Step 3: Announcing the number of items on CodePen.
Add a landmark
With little effort, you've made great improvements for screen reader users, but there's one more thing you can do. The navigation is semantically still just a list of links and it's hard to tell that this specific list is the main navigation of your website. You can turn this ordinary list into a navigational list by wrapping the