Patterns / intermediate

Navigation shells with crawlable links and responsive behavior

Navigation is both an interface and a crawl path, so it should be real links before it becomes an interaction.

A navigation shell has two jobs: help people move through the site and expose important paths to crawlers. The first version should be plain, crawlable HTML links. Enhancement can come after that.

<nav aria-label="Primary navigation">
  <a href="/field-guide">Field Guide</a>
  <a href="/patterns">Patterns</a>
  <a href="/debugging">Debugging</a>
  <a href="/demos">Demos</a>
</nav>

This is not primitive. It is resilient. A crawler can follow it, a keyboard user can tab through it, and the links still work without JavaScript.

Navigation is infrastructure, not decoration. It appears on many pages, so small mistakes spread widely: a hidden link that cannot be reached by keyboard, a menu that only opens after hydration, or a current-page state that is visual but not semantic. Start with real anchors and a clear hierarchy, then add styling and disclosure only where they improve the experience.

Use the fewest navigation regions that explain the site. A primary nav should contain the main sections. Footer navigation can carry legal and secondary links. Breadcrumbs can show location inside a deeper hierarchy. Do not make every link appear in every region. Repetition makes scanning harder and can blur which paths matter most.

Responsive does not always mean hidden

Many sites collapse navigation too early. If there are five short links, wrapping them may be better than hiding them behind a menu button. Reserve disclosure navigation for cases where the number of items or viewport constraints truly require it.

.primary-nav {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}

This pattern is boring in the best way. It avoids JavaScript state, avoids focus management complexity, and keeps important sections visible.

Wrapping needs design attention. Keep gaps consistent, avoid tiny tap targets, and make sure wrapped links do not overlap the brand or page controls. A nav that wraps to two lines can still be professional if the header is allowed to grow naturally. A nav that must stay one line at every width usually ends up shrinking text, clipping labels, or hiding important sections too early.

When a disclosure menu is necessary, treat it as an interaction with state. The button needs an accessible name, the expanded state should be exposed, focus should move predictably, and the menu should close in understandable ways. Those requirements are manageable, but they are not free. If visible links solve the problem, visible links are the stronger pattern.

Use aria-current

<a href="/debugging" aria-current="page">Debugging</a>

aria-current gives assistive technology a clear signal and gives CSS a stable styling hook.

Use the value that matches the context. aria-current="page" is appropriate for the active page in site navigation. In breadcrumbs, the final item can use the same value or be rendered as plain text. Do not use current-page styling only through class names if the state matters to navigation.

Current states should not resize the navigation. If the active state adds a border, reserve that border in the default state with a transparent color. If it changes font weight, make sure the wider text does not push neighboring links. Navigation should not jitter as users move between pages.

Keep crawl paths and user paths aligned

The links that matter to readers should be available in HTML. If a menu is generated only after client-side JavaScript runs, users and crawlers may see a weaker site structure than intended. Static site generators make this easy: render the anchors in the template, then enhance them if needed.

Avoid linking to thin or dead-end pages from the global shell. A contact link that does not provide a contact method, a category with no useful context, or a placeholder route can make the site feel unfinished. Global navigation is an editorial promise. Every link should lead to something useful.

Design for touch, keyboard, and zoom

Navigation links should remain readable and reachable at narrow widths and zoomed text. Use normal document flow rather than absolute positioning whenever possible. If the header sticks, make sure skip links still work and focused elements are not hidden behind it. If the nav scrolls horizontally, ensure it is obvious and keyboard accessible; hidden horizontal nav can strand users who do not use touch.

Dropdowns and mega menus need even more care. They should not be required for the only path to important pages unless the trigger works across input types. Hover-only navigation fails on touch screens and can be frustrating for keyboard users. If a menu opens on hover, it should also open by focus or button activation.

Match the shell to the content model

A small educational site can use a flat shell: Field Guide, Patterns, Debugging, Demos, About. A large documentation site may need section landing pages, side navigation, and breadcrumbs. The CSS should follow that content model. Do not add a complex app-style nav when the site has only a few stable sections, and do not hide a deep documentation structure behind a single menu.

The best navigation shell is easy to ignore because it works. Links are real, states are clear, wrapping is intentional, and each route earns its place in the global frame.

References