Skip to main content

Speed up navigation between pages


Basic idea - navigating between pages is slow, because:

  • browser waits for network response
  • it is expensive to redraw the whole page from scratch. Much faster would be to replace innerHTML of the document. At least this is common belief, but there are nuances to that.

History #

First solution appeared in 2010. See defunkt/jquery-pjax

Around 2015 “olympic torch” was taken over by turbolinks. Which was part of Rails stack and later replaced by Turbo Drive.

Around the same time there were also:

In 2018 Google jump in on that boat with quicklink

Note: later doesn’t mean better, because development didn’t stop at the release date. For example, swup recently released v4.

Is it still alive? #


One would think that with SPA trend (started around 2015) nobody would care about this kind of solutions, but static website still popular. For example Hugo, Astro and others

The devil is in the details #

I put all those libraries in one category but they are actually different and use different assumptions. For example,

Browser history #

So we have two main approaches:

  • don’t take over browser navigation
  • take over browser navigation
    • pros:
      • hard to integrate
    • cons:
      • animations are possible
      • state of the page can be preserved but needs additional work
    • examples: pjax, barba, swup, astro-spa

Adaptability #

Besides browser navigation we need to take into account:

  • we don’t want to prefetch all the links
    • quicklink uses Intersection Observer to detect links within the viewport
    • Other approach is to do this on hover, focus, tap
    • Some libraries allows to specify which links to prefetch
    • Or we can statistically guess
  • we don’t want it to do while browser is busy doing something else. You don’t want to degrade user experience
  • Making additional requests on mobile devices may cost user additional money
    • quicklink uses navigator.connection.effectiveType to detect slow networks, and navigator.connection.saveData to detect data-saver mode

Main subject is to speed up navigation between pages, but there are related functionalities:

I mainly concern myself with static web sites, but in the context of dynamic websites there is so called “HTML over wire” approach:

Complexity with browser history #

Basic implementation can look like this

  1. Add global click event listener
  2. on click you fetch remote content
  3. extract element that needs to be replaced (for example main)
  4. replace content with target.innerHTML = response
  5. Push new item to history with history.pushState(state, "", url);

But you need to take care of:

  • removing event handlers from old HTML
  • attaching event handlers to new HTML
  • replacing title, maybe announce it to screen reader
  • replacing styles
  • replacing scripts
  • maybe provide a hook so that it would be possible to integrate analytics
  • scrolling to top of the page
  • listen to history for back navigations
  • maybe resolve relative links
  • it doesn’t preserve state of scroll or tabs

It is an error-prone approach.

To be continued… #

While I was doing the research on the subject I stumbled upon:

I will need more time to finish the research

Read more: Server-side UI Components, Rails UI components