clear current page UX
Yesterday in Perception of Speed I wrote about how clicking a link doesn’t immediately clear the screen. Instead, browsers wait “until the next page arrives” before clearing the screen. This improves the user experience because instead of being unoccupied (staring at a blank screen), users are occupied looking at the current page.
But when exactly do browsers clear the screen? Pick what you think is the best answer to that question:
- when the first byte of the new page arrives
- when the new page’s BODY element is rendered
- when DOMContentLoaded fires
- when window.onload fires
I would have guessed “A”. In fact, I’ve been telling people for years that the current page is cleared when the new document’s first byte arrives. That changed yesterday when my officemate, Ilya Grigorik, wondered outloud when exactly the browser cleared the page. It turns out the answer is at or slightly before “B” – when the new page’s BODY element is created.
Here’s a test page that helps us explore this behavior:
The page contains a script that takes 10 seconds to return. (You can change this by editing the value for “delay” in the querystring.) I used a script because they block the browser from parsing the HTML document. Placing this script at different points in the page allows us to isolate when the screen is cleared. The three choices for positioning the script are:
- top of HEAD – The SCRIPT tag is placed immediately after the HEAD tag, even before TITLE. This is our proxy for “first byte” of the new document.
- bottom of HEAD – The SCRIPT tag is placed right before the /HEAD tag. There are a few STYLE blocks in the HEAD to create some work for the browser while parsing the HEAD. This allows us to see the state right before the BODY element is created.
- top of BODY – The SCRIPT tag is placed immediately after the BODY tag. This allows us to isolate the state right after the BODY element is created.
Background colors are assigned randomly to make it clear when the BODY has been rendered.
I ran these three tests on the major browsers to measure how long they waited before clearing the page. I assumed it would either be 0 or 10 seconds, but it turns out some browsers are in the middle. The following table shows the number of seconds it took before the browser cleared the page for each of the three test cases.
|Table 1: Number of seconds until page is cleared|
|Browser||top of HEAD||bottom of HEAD||top of BODY|
Let’s look at the results for each position of the script and see what we can learn.
#1: Top of HEAD
In this test the 10 second script is placed between the HEAD and TITLE:
<head> <script src=... <title>...
Even though the HTML document has arrived and parsing has begun, none of the browsers clear the screen at this point. Therefore, browsers do NOT clear the page when the first byte of the new page arrives. Firefox, IE, and Safari don’t clear the screen until 10 seconds have passed and the BODY has been parsed (as we’ll confirm in test #3). Chrome and Opera have interesting behavior here – they both clear the screen after 4-5 seconds.
The major browsers differ in how they handle this situation. Which is better – to preserve the old page until the new page’s body is ready, or to clear the old page after a few seconds? Clearing the screen sooner gives the user some feedback that things are progressing, but it also leaves the user staring at a blank screen. (And the hypothesis from yesterday is that staring at a blank screen is UNoccupied time which is less satisfying.)
Do Chrome and Opera intentionally clear the page to provide the user feedback, or is something else triggering it? Ilya was doing some deep dive tracing with Chrome (as he often does) and found that the screen clearing appeared to coincide with GC kicking in. It’s not clear which behavior is best, but it is interesting that the browsers differ in how long they wait before clearing the screen when the BODY is blocked from being parsed.
Another interesting observation from this test is the time at which the TITLE is changed. I was surprised to see that all the browsers clear the old title immediately, even though the old page contents are left unchanged. This results in a mismatch where the title no longer matches the page. Every browser except one replaces the old title with the URL being requested. This is a bit unwieldy since the URL doesn’t fit in the amount of space available in a tab. The only exception to this is Firefox which displays “Connecting…” in the tab. It’s further interesting to note that this “interim” title is displayed for the entire 10 seconds until the script finishes downloading. This makes sense because the script is blocking the parser from reaching the TITLE tag. We’ll see in the next test that the TITLE is updated sooner when the script is moved lower.
#2: Bottom of HEAD
In this test the 10 second script is placed at the end of the HEAD block:
<script src=... </head> <body>
The results for clearing the page are the same as test #1: Firefox, IE, and Safari don’t clear the page for 10 seconds. Chrome and Opera clear the screen after 4-5 seconds. The main point of this test is to confirm that the browser still hasn’t cleared the page up to the point immediately before parsing the BODY tag.
The title of the new page is displayed immediately. This makes sense since the TITLE tag isn’t blocked from being parsed as it was in test #1. It’s interesting, however, that the browser parses the TITLE tag and updates the title, but doesn’t clear the old page’s contents. This is worse than the previous mismatch. In test #1 an “interim” title was shown (the URL or “Connecting…”). Now the actual title of the new page is shown above the content of the old page.
#3: Top of BODY
In this test the 10 second script is placed immediately after the BODY tag:
</head> <body> <script src=...
Since nothing is blocking the browser from parsing the BODY tag, all but one of the browsers immediately clear the old page and render the new body (as seen by swapping in a new random background color). However, because the very next tag is the 10 second script, the rest of the page is blocked from rendering so the user is left staring at a blank page for 10 seconds. The browser that behaves differently is Opera – it maintains its ~4 second delay before erasing the screen. This is curious. What is it waiting for? It parses the new BODY tag and knows there’s a new background color at time 0, but it waits to render that for several seconds. Does downloading the script block the renderer? But what causes the renderer to kick in even though the script still has numerous seconds before it returns?
For these contrived test cases Opera has the best behavior in my opinion. The other browsers leave the user staring at the old page for 10 seconds wondering if something’s broken (test #1 & #2 for Firefox, IE, and Safari), or leave the user staring at a blank page for 10 seconds while rendering is blocked (test #3 for Chrome, Firefox, IE, and Safari). Opera always compromises letting the user watch the old content for 3-4 seconds before clearing the page, and then shows a blank screen or the new body for the remaining 6-7 seconds.
These examples, while contrived, yield some real world takeaways.
- Browsers generally clear the page when the BODY is parsed, not when the first bytes arrive. I say “generally” because during testing I was able to get browsers to clear the page before BODY by adding async and inline scripts, but it was very finicky. Changing just a few lines in innocuous ways would change the behavior such that I wasn’t able to nail down what exactly was causing the page to be cleared. But all of this was after the page’s first bytes had arrived.
- It’s unclear what is the best user experience for clearing the page. The major browsers have fairly divergent behavior, and it’s not clear whether these differences are intentional. Transitioning from one page to the next is an action that’s repeated billions of times a day. I’m surprised there’s not more consistency and data on what produces the best user experience.
- Avoid frontend SPOF. I’ve written (and spoken) extensively about how loading scripts synchronously can create a single point of failure in your web page. This new information about how and when the old page is cleared adds to the concern about slow-loading synchronous scripts, especially in light of the inconsistent way browsers handle them. Whenever possible load scripts asynchronously.