Skip to content

Back to projects

Frontend

Instant navigation without giving up a site that works with zero JS

· 6 min

A mostly-static, server-rendered site, where every route exists as a real HTML file, has a real cost on every internal navigation: clicking a plain link discards the entire page and rebuilds everything, reparsing CSS, re-checking fonts already in cache, re-running every script from scratch, even though the header, footer, and most of the navigation are identical from one page to the next.

Illustration of two chain links with a lightning bolt

The hidden cost of a plain link

In practice, most of what gets reloaded on every navigation doesn't actually change: the header, the footer, and the CSS/JS already loaded stay exactly the same from page to page. Only the main content is genuinely different, but a plain link doesn't know that, and pays the cost of rebuilding the whole page from scratch anyway.

Intercept, fetch, swap

The fix was a minimal client-side router: it intercepts clicks on same-origin internal links, fetches the target page's HTML via fetch, and swaps only a fixed handful of regions, the skip-to-content link, header, main content, and footer, instead of replacing the whole document. CSS, fonts, and scripts already loaded stay untouched; only the content that actually changed travels over the network.

Progressive enhancement, not a dependency

The key point is that every route still exists as a real, independently fetchable HTML page, with no client-side framework needed to render it. If the fetch fails, offline, a 404, or JavaScript is disabled, the router simply steps aside for a normal full-page navigation, and the service worker's offline fallback still applies exactly the same. The router is an enhancement layered on top of a site that already works completely without it, never a requirement for it to function.

The result

Navigating between pages feels instant, because only the content that actually changed gets fetched and rendered, while every page remains independently crawlable, linkable, and fully functional with JavaScript off, with no client-side framework or hydration step required to make that happen.