Optimal webpage structure
March 2nd 2013 by Samuel Rossille
Everybody who browses the web or uses a web application wants pages to load fast. There's a lot of litterature about minimizing the number of requests, optimizing cache management, minimizing the size of images, etc... About these matters, I would recommend this article. It helped me a lot with this very website.
But there are some ways to improve things even further. They are not very widespread, but quite simple to setup. In this article, I will explain how the structure of the page itself can greatly impact the loading time of the page, and how to minimize that time.
It's all about latency
Let's have a look at the statistics for a typical 23 Ko webpage that returns with HTTP 200 OK served by a server that is not overloaded. First thing to notice: 168 milliseconds waiting, 8 seconds to receive the content. Now let's look at a simple "normal" document, with one stylesheet, one script, and some content:
And this is what happens when we load this document:
Let nothing stand in your way.
There are two things that can block the browser and prevent it from displaying the page:
- When a script node is met, the browser cannot go on rendering after the node before executing the script, because the script could write to the document with
document.write(). So the rendering has to wait until the script is downloaded and executed.
- All the stylesheets must be available to display the page with it's final look.
So in our situation, the three request must be finished before the page is rendered with it's final look. What can we do ?
On the article I recomended earlier, the author recommends to merge the stylesheets together to have just one. I'll go even further and say: merge all the stylesheets in the document's header. That will not increase the amount of data to download, and it will reduce the number of requests by one.
The important thing to understand is that several files helps with readability of the codebase, but it doesn't help at all the browser that has to pull the content.
Note: the merge can be done during a publishing phase, or dynamically with PHP or JSP, so while working you still have several files, which is more convenient. So let's merge the stylesheet into the header and see:
Now the page loading statistics look like this: That's already better, but not yet good enough. There is one more thing to do. The script in the header is still blocking the rendering, because the browser wants to wait to execute it before going further, just in case the script wants to write in the DOM. A good workaround to that issue is to put the script just before the end of the body.
That will still prevent the DOM ready event to fire, but the page will have it's final look when the first request has completed instead of having to wait for the second. The statistics of the page loading are still the same, but now the page seems ready to the eye between the two requests, instead of having to wait for the second one to complete: Just by embeding the stylsheet and moving one script tag at the end of the file, we have reduced the time needed from 236ms to 100ms.
Actually there is just one drawback: you loose the benefit of caching the CSS file. On a typical website, pages can change everyday, but the css much less often. So the css files are likely to be setup with a much longer validity duration. We saw that embeding the CSS will speedup the loading of a page for a first visitor by roughtly 100ms (one roundtrip to the server), but since we loose the benefit of caching, we loose roughly 20ms (the receiving time of the CSS code) for a typical css file for all subsequent visits. So it's up to you to see what you prefer.
My personnal position is that 100ms for all visits is better than 200ms for the first visit, then 70ms for next visits. Note: it's also possible to embed the scripts themselves in the page, but it might not be such a good idea, because you still loose the benefit of caching the scripts, for something that's not necessary because putting them at the end of the body tag will still let the page display correctly while you wait for them to be downloaded (or receive the 304 NOT MODIFIED).
So for me, the optimal webpage structure is:
- All the CSS embeded in the header.
- All the scripts referenced by script tags just before closing the body tag.