Aim for a Good Balance
1 <nav id="r-skiplinks"> 2 <h6 class="r-sr-only">Bereichsnavigation</h6> 3 <div class="r-skl-nav"> 4 <a class="r-skl" href="#r-search"><span>Zur Suche</span></a> 5 <a class="r-skl" href="#r-usr-nav"><span>Zum User Menu</span></a> 6 <a class="r-skl" href="#r-main-nav-rezepte"><span>Zum Hauptmenu / Rezepte</span>\ 7 </a> 8 <a class="r-skl" href="#r-main-nav-magazin"><span>Zum Hauptmenu / Magazin</span>\ 9 </a>10 <a class="r-skl" href="#r-main-nav-community"><span>Zum Hauptmenu / Community</s\11 pan></a>12 <a class="r-skl" href="#r-main-nav-videos"><span>Zum Hauptmenu / Videos</span></\13 a>14 <a class="r-skl" href="#main"><span>Zum Content</span></a>15 <a class="r-skl" href="#r-footer"><span>Zum Footer</span></a>16 </div>17 </nav>
What you just read is code from a German website, with “skip” links that are hidden by default, and shown when “tabbing” through the page. Nothing spectacular here; in fact, a good practice when there are large blocks of navigation between the user’s focus and the main content. (WebAIM, to name just one, has a good intro on skip links.)
Let’s look at the markup.
The nav
container looks appropriate, given that the section offers navigation. That also holds in the case of in-document navigation.
The heading level appears dubious (is it an h6
?), but you’ve seen me tread lightly around these. (After all, correcting a heading level boils down to changing two digits.)
Then it gets a little weird: A div
element hosting a list of hyperlinks, which in turn contain span
elements. The keyword here is certainly “list,” as in most if not all cases, this asks for a list element (usually one of ul
, ol
, or dl
), as with:
1 <ul> 2 <li><a href=#r-search>Zur Suche</a> 3 <li><a href=#r-usr-nav>Zum Nutzer-Menü</a> 4 <li><a href=#r-main-nav-rezepte>Zum Rezepte-Menü</a> 5 <li><a href=#r-main-nav-magazin>Zum Magazin-Menü</a> 6 <li><a href=#r-main-nav-community>Zum Community-Menü</a> 7 <li><a href=#r-main-nav-videos>Zum Videos-Menü</a> 8 <li><a href=#main>Zum Inhalt</a> 9 <li><a href=#r-footer>Zum Footer</a>10 </ul>
With this list change, I also snuck in three more changes:
- Removing the
span
elements: Some of you have seen me do this in the past, working with the assumption that these aren’t needed and that their effect can be accomplished by other means. (I’ll repeat, too, how this assumption may be wrong. The use of helper elements can be an option.) - Removing the classes: That type of repetition does and must constitute a red flag—effectively, it’s a violation of Don’t Repeat Yourself. CSS has always offered the option to style based on the context; if you look at the original code, meaning a selector like
.r-skiplinks li
(or.r-skl-nav li
, if we kept thediv
container class). - Fixing and rewording the navigation text: It contained some typos (menu, Menü in German, is written with an umlaut), and it was not as easy to parse as it could be (notice the Zum Hauptmenu [sic] references? this kind of frontloading slows down scanning and listening).
If you push the context argument (in 2.) further, you notice how this can be applied to the other classes, too: There’s nothing preventing us from working with one class or ID for the whole section—or none, given how powerful CSS selectors are by now. (Haven’t you ever wondered about classless development? I call it the “lost paradigm”.)
This leads us to the following, final piece of code (with aux
as a tentative name for auxiliary navigation):
1 <nav id=aux> 2 <h6>Bereichsnavigation</h6> 3 <ul> 4 <li><a href=#r-search>Zur Suche</a> 5 <li><a href=#r-usr-nav>Zum Nutzer-Menü</a> 6 <li><a href=#r-main-nav-rezepte>Zum Rezepte-Menü</a> 7 <li><a href=#r-main-nav-magazin>Zum Magazin-Menü</a> 8 <li><a href=#r-main-nav-community>Zum Community-Menü</a> 9 <li><a href=#r-main-nav-videos>Zum Videos-Menü</a>10 <li><a href=#main>Zum Inhalt</a>11 <li><a href=#r-footer>Zum Footer</a>12 </ul>13 </nav>
Watch Out!
Not that you planned to do this but—don’t use the hidden
attribute for navigation sections like this. When writing this chapter, I made the enthusiastic mistake of deeming this a possible use case for hidden=until-found
. If you don’t know it, hidden=until-found
reflects a relatively recent addition to the previously Boolean hidden
attribute. (The until-found
value and corresponding “hidden until found” state indicate that “the element is hidden like [in] the hidden state but the content inside the element will be accessible to find-in-page and fragment navigation.”)
That seemed to be useful here—but, as peers like Sara Soueidan and Scott O’Hara were quick to point out on a spontaneous Twitter poll, isn’t true.
Now that this warning anecdote is out of the way, let’s consider the method of hiding navigation. A CSS or accessibility book might want to approach this authoritatively, as I’ve been avoiding the topic in this series of HTML books. Not only does it go beyond the focus on HTML—there already are great articles on accessibly hiding elements. The A11Y Project’s Hide Content, 18F’s Hidden Content, and Orange’s Accessible Hiding provide good information, to list a few.
But what happened to the “good balance” to aim for, in line with the topic of this chapter?
Web development requires balance, because there are many things that matter. Here, we value conformance, minimalism, code quality. But there’s content quality, accessibility, usability, user experience, performance, SEO, and many more priorities. If we don’t think in terms of balance, we start optimizing on one (or few) dimensions, and may even over-optimize. (See the coming “tip” section for more thoughts.)
When you look at the optimized code, then it still pretty much matches this book’s priorities of valid and minimal and quality code. But for “skip” links, that isn’t worth anything if it’s done in a way that’s not accessible; and it’s also not worth much if we forget about building it so that it’s usable. While I owe you more about defining and identifying paths to a good balance, understanding the idea of a balance is where it all starts.
Tip
Beware of over-optimization, or one-dimensional optimization. Web design and development cover many different areas, all of which we can optimize for: Think of the aforementioned factors such as SEO, performance, accessibility, usability and user experience, technical conformance, legal compliance, general code quality, &c.
The problem is that when we push too hard with one area or factor, not only does this get costly (it requires more and more work to identify ever smaller improvements), it will also at some point involve trade-offs that negatively affect other areas.
I tried to describe the problem in a post: One-Dimensional Website Optimization Considered Harmful. Of course, all I want to say is to be mindful, and to make conscious decisions. That should guard against over-optimization.