A lot has changed in the fifteen years that I have been developing websites. The biggest changes happened in the browser, completely restructuring how normal web services are built. Now everybody expects your website to have at least a few dynamic elements, be it your login form, your shopping cart or a contact form.
Some websites are actually web apps, which means that they can be developed completely differently and be written as browser apps that only communicate with the server to get the dynamic data. In this case, the web server is only in charge of providing the app itself and exposing some API (mostly a JSON API) the app can consume. Webmail services, task trackers, calendars etc… are good examples of this. They are not what this post is about.
Most websites can’t and shouldn’t be built like web apps, since they need to be crawlable by search engines and want to be displayed as fast as possible instead of requiring the user to first download the app (that can be a few megabytes).
This is why the approach for normal websites is typically to use a web server to generate HTML sites and provide all the dynamic functionality with HTML. You would then have a normal HTML login form, which posts the data to the server, menus that are rendered differently on the server depending on if the user is logged in or not, displaying session info, etc…
This approach is problematic for multiple reasons though:
So in order to also have an HTML only version, you actually create a worse website for 98% of your users to accommodate 2%.
This is where the concept of stateless HTML comes into play.
When I talk about stateless HTML I mean that everything representing a user state (authentication state, geographic position of the user, etc…) should not affect the HTML you render. In other words:
Every user should get the exact same HTML for the same URL, regardless of state, geographic location or time
The first thing to do is think of which parts need to be crawlable by search engines. In the case of a recipe website, the “About” page and the single “Recipe” pages would be a good example of pages that need to be discoverable when people search for them.
Everything that represents data that is not affected by who is looking at it and from where.
The user menu (login, my account, my recipes, etc…), recipes that might suit the user's taste, a contact form and everything that is user specific and dynamic are examples of content that do not need to be included in your HTML.
So you can see that this concept is nothing new.
ages of stateless HTML
Performance. Serving static HTML sites can be heavily cached (by the browser or a load balancer). They only need to change when the content changes, which normally happens rarely.
More robust hosting. By completely separating your static content from your dynamic content, your HTML sites are less prone to failure. Depending on the webapp you build, your site could even be served properly if your database crashed, only disabling all authentication and dynamic content (which is far better than your whole page displaying a “database error”).
Better user experience. In the next section I’ll explain how stateless HTML can drastically improve the UX of your webapp.
Taking it to the next level
In most cases, pages are more complex than adding a message board. You often have authentication, account management, shopping carts, rating systems, etc… At this point, most developers will start implementing this functionality, and they normally start writing the HTML for it.
In this section I will try to paint the complete picture of how a fully functioning stateless HTML website would work, and what UX benefits you get from it.
Generating the HTML pages
First of all, you still need to create your typical HTML pages. I will give a very simple example of how such a page could look like:
app.js) gets executed and does the following things:
- Check if the user is logged in (with cookies and/or an AJAX request to the server)
- Create the appropriate
.account-menucontent (depending on the user authentication state)
- Parse the document to find all relative links, pointing to other pages
I think that all of those points are pretty obvious, except for the last one, which is the subject of the next chapter.
Load all content dynamically
By putting all your content in the
#main section, and always serving the same HTML blocks before and after, you make it possible to dynamically load your content and simply exchange it for every page, without needing to implement another representation of your content on the server.
You then attach a
click event handler on those links, “disable” the default behavior (by calling
event.preventDefault()) and add your own click handler.
What the implementation should do, is:
- Create an AJAX request to the location (eg.:
- Change the URL in the browser with the history API (this way, the back and forward buttons still work in the browser).
- Show a loading animation that the content is now being loaded.
- When the content is loaded, parse it to extract the contents of
#main(you can help yourself there by adding markers in your HTML) and replace the content of your current
#mainsection with the one you just loaded.
- Make sure that you handle all the links in your new
Since all your pages are static HTML files anyway, you just get this “in page loading” functionality for free. Your links are still completely valid (you can just reload the page or send the link to someone else), there is no additional maintenance of two separate versions (the one to be served as pure HTML and the one that gets loaded with AJAX), and the initial delay of showing the account menu or determining the user’s authentication state will not be reproduced since the page is not actually reloaded.
The long-lasting struggle with slow browser adoption and stale browsers (notably IE6) is also a thing of the past, allowing developers to actually use modern features without needing to implement fallbacks for all of them to support their customers.
As stated before, none of this is really new. The main purpose of this post was to provide strict guidelines on how to build your web application in order to get the best result for the least effort:
- Write stateless HTML
- Handle page loads transparently with AJAX by loading and parsing your HTML files