Many people in the web community believe that SPAs (single page applications) give users a superior user experience.
But most of the time, SPAs give users an unfamiliar, inconsistent, fragile experience. Not only that, but SPAs are much harder and costlier to design, build and test.
In this article, I'll explain why that is. But first, let's define the meaning of a SPA.
What's an SPA?
You might associate MVC, data flow and client-side templating with SPAs. But these things are not the defining characteristics of an SPA. In actual fact, you can use all of them to create rich, but more traditional ROCA-style sites.
1. Going back and forward quickly and reliably
Browsers store history so that pages load quickly when the user clicks back. Daniel Puplus explains in Building Single Page Applications that:
“When a user presses the browser’s back button they expect the change to happen quickly and for the page to be in a similar state to how it was last time they saw it.
“In the traditional web model the browser will typically be able [to] use a cached version of the page and linked resources.
“In a naive implementation of a SPA hitting back will do the same thing as clicking a link, resulting in a server request, additional latency, and possibly visual data changes.”
- storing pages in memory, local storage, client-side databases or cookies.
- determining when to retrieve the cached pages and when to invalidate them.
As part of (2) there will need to be logic to work out whether the user is changing the URL manually—by clicking a link or typing a URL directly in the location bar. Or by pressing the browser back or forward buttons. This is not achievable to my knowledge.
2. Scroll position
Browsers remember the scroll position of pages you've visited. Daniel Puplus, again, explains how SPAs cause trouble here:
“Lots of sites get this wrong and it’s really annoying. When the user navigates using the browser’s forward or back button the scroll position should be the same as it was last time they were on the page. This sometimes works correctly on Facebook but sometimes doesn’t. Google+ always seems to lose your scroll position.”
To fix this, we have to write code to store, retrieve and apply the correct scroll position when the user navigates back and forth.
3. Cancelling navigation
When a user clicks cancel, or clicks a link, the browser will stop any in-flight requests.
SPAs retreive entire (data for) pages using AJAX. So there could be several requests in-flight. The first request could finish last. Or, a user could click (and therefore request) the same link twice.
This is problematic because its inefficient, will use up people's data unnecessarily and cause visual glitches as subsequent requests finish that should have been cancelled.
Again we need to write code to handle all these use cases. And to let users cancel requests explicitly, we need to put a custom cancel button on the interface which is undesirable to say the least.
4. Handling unsaved changes
In a traditional web application, we can warn users of unsaved changes using the
beforeunload event. But SPAs don't navigate, which means this event won't fire. So we have to reimpliment this ourselves from scratch.
5. Search engine ranking
Search engine optimisation (SEO) is usually an afterthough when building SPAs. But retrofitting this is difficult and costly.
Creating a separate dedicated server-rendered site for search engines to access is wasteful and means having to maintain two separate codebases.
With a traditional, ROCA style website, we get this for free.
6. Loading CSS and JS
Analytics tools track page views by default—you simple add the analytics code to the page and that's it. But SPA pages aren't real pages.
This means we have to add logic to the application to make sure the analytics tool picks up new pages being loaded in without a refresh.
8. Automated functional testing
In relation to the previous point, automation tools like Selinium know when a page has loaded. But automation tools don't explicitly know a page loaded with AJAX has loaded.
This means tests will be more long winded to write (by having to handle timeouts etc) and they'll be slower to run.
9. Memory leaks
AS SPAs don't load pages, the initial page will stay open for a long time. This increases the chance of memory leaks which can cause the browser to crash and battery powered devices to drain quickly.
10. Loading indicators are inaccurate
The native browser loading indicator provides an accurate, predictable and familiar experience to users across all sites the user visits in their browser.
As SPAs use AJAX to render pages, we need to create a custom loading indicator from scratch. Besides the extra work, custom loading indicators tend to be inaccurate and unfamiliar.
This can cause users to click the link again which creates a frustrating experience.
11. It's going to fail
As a result, when there's a failure, the result will be a blank screen. Putting the onus on the user to refresh the page, use another browser or simple leave.
12. They're probably slower
SPAs are very likely to be slower than server-side rendering because:
- loading and rendering a page with AJAX is usually slower
- extra coded is needed to fix the issues above
“Fun fact: it takes a Moto G4 about 15.66 times longer to evaluate 2.1MB of (decompressed) JS than it does to decode a 10MP image.”—Harry Roberts
13. They're not accessible by default
Read One-page-applications are not accessible by Craig Abbott.
14. They just don't feel right
Read Why I hate your Single Page App by Stefan Tilkov.
So many people think SPAs provide faster and better experiences but in reality they create a slower, inconsistent, frustrating and inaccessible experience.
And to make matters worse they are actually harder to design, build and test. And I'm not the only one to have experienced this.
Twitter, Lifehacker and Delicious reverted to traditional architectures for these reasons which you can read below:
Sign up to Good Design
I'll send you one email per month about nailing the basics, avoiding complexity and making things work for everyone.