One of the challenges that comes with pure JavaScript UI is a nasty little user experience problem that I'm calling "Flash of Uninitialized JavaScript UI," or FOUJUI (rolls right off the tongue).
FOUJI, similar to FOUC, occurs when:
When an user loads a page that meets these conditions, they briefly see a version of your site that doesn't look correct, as if it hasn't been fully loaded. Styles will be applied, but the UI will look incomplete.
Why?
Let's think about what's happening when you load a site that uses a rich JavaScript front-end (assuming best practice CSS and JavaScript patterns):
The problem for users is that your site is "visible" before the initialization code runs to build your JavaScript UI. They see the styled static HTML before JavaScript has the chance to apply the needed transformations to your DOM.
To put this in context, I was having this problem in the Kendo UI Feed Reader demo. The problem was particularly pronounced on devices, like the iPad, where loading and execution of the site JavaScript is slower. Here's what users would see when loading the demo:
Then, after the site initialization scripts ran and the Kendo UI widgets rendered, users would see the final (proper) site interface:
Quite a difference! The uninitialized view is usually only visible for a split second (sometimes longer on slower device browsers), so you could easily dismiss this as an ignorable inconvenience. But we want to give our users a better experience. We want to eliminate the FOUJUI.
Solving the Flash of Uninitialized JavaScript UI can be done in a few different ways. The core problem is that the static HTML loaded on the initial request does not represent the final HTML as it will exist after JavaScript modifies the DOM. Solutions:
For the Feed Reader demo, everything is happening with static HTML and JavaScript, so option #1 (rendering the initial HTML on the server) is not an option. That means I'll pursue solution #2: a JavaScript loading screen.
There are probably 1,001 ways to build a JavaScript loading screen, but for simplicity, I elected to use some simple HTML and CSS that would cover my entire application while the page is initializing.
HTML
<div id="preLoad"> <div> <img src="styles/BlueOpal/loading-image.gif" alt="Loading Image" style="width:48px;" /> <br />Loading... </div> </div>
CSS
#preLoad{ width:100%; height:100%; background:#FFF; position:absolute; top:0; } #preLoad div{ position:absolute; top: 50%; left: 50%; height:60px; margin-top: -30px; margin-left: -24px; }
Now, when the Feed Reader app loads, rather than seeing the uninitialized HTML (or any of the app, for that matter), users will see my simple loading screen:
Cool. That's better. Users understand loading screens, and it's a lot less jarring than seeing the FOUJUI effect.
But now I need to make the loading screen "go away" when the JavaScript UI is ready. Doing this requires two changes to my demo:
Simple enough. In the "init" event for my app (see the source), I add this single line of code that is executed after all initialization steps are complete (including the initialization of my Kendo UI widgets):
//Trigger event indicating init is complete $(document).trigger("FEED_READER_APP_READY");
And then, to handle this event when it's triggered, I wire-up a binding in my main page that will hide my loading screen:
$(document).bind("FEED_READER_APP_READY",function(){ $("#preLoad").fadeOut(); });
And that's that. Now users will always see the loading screen while my app is initializing, and when the UI is ready, the loading screen will fade out to reveal a ready-to-work application. No FOUJUI!
While the functional problem has been solved at this point, I quickly discovered that the jQuery "fadeOut" animation (which uses JavaScript) does not work well on all devices. The animation is choppy (at best) on mobile devices due to the weaker JavaScript processing.
We can improve this effect and make it buttery smooth on all devices by leveraging CSS3 Transitions. Browsers hardware accelerate CSS animations/transitions, giving CSS3 the power to speed-up any app (especially on mobile devices).
Browser support for CSS3 transitions is strong, but even browsers that don't support transitions will gracefully degrade to a functional, "direct" transition. So there's no reason not to use this technique.
The first step in this refactoring is to add the cross-browser CSS3 rules that define my transition. To achieve the same "fade out" effect, I will use the CSS opacity and visibility settings to hide my loading screen.
#preLoad{ width:100%; height:100%; background:#FFF; position:absolute; top:0; -moz-transition: visibility 0s linear 1s, opacity 1s ease-in-out 0s; -webkit-transition: visibility 0s linear 1s, opacity 1s ease-in-out 0s; -o-transition: visibility 0s linear 1s, opacity 1s ease-in-out 0s; transition: visibility 0s linear 1s, opacity 1s ease-in-out 0s; }
This code basically says:
If opacity is used without visibility, then the entire app would remain "blocked" by the an invisible element after the loading screen fades out (opacity=0). By combining with visibility, the loading screen will fade out and be properly hidden. The delay ensures the opacity change animation will complete before the element is hidden.
How do we trigger the CSS3 fade out transition? By simply changing the CSS opacity and visibility properties to their desired target values on our loading screen element:
$(document).bind("FEED_READER_APP_READY",function(){ $("#preLoad").css("opacity","0").css("visibility","hidden"); });
When these values change, the browser will calculate the necessary animated transition to get from the original values to the new values, using the specified timing function ("ease-in-out") to shape the animation path.
The result: a fade out transition that looks smooth on desktop and mobile browsers.
With these simple techniques applied, our user experience is now much better. When the application loads, users briefly see a loading screen, hiding the uninitialized HTML UI, and then a smooth, animated transition presents the app when it's ready.
You can try the updated Kendo UI Feed Reader demo for yourself to see this in action.
For those of you using a version of Internet Explorer less than 10 (the first from Microsoft to support CSS3 Transitions), here is a quick animated example showing what other browsers are seeing (in rough animated GIF format):
The transition to JavaScript-driven applications will increasingly require developers to adopt "new" techniques to deliver premium user experiences. Eliminating the disruptive FOUJUI is one such problem that can easily be solved with minimal modification and code. Hopefully this post gives you some ideas for improving your own JavaScript application experiences, and hopefully you'll join me in eliminating FOUJUI!
Todd Anglin is Vice President of Product at Progress. Todd is responsible for leading the teams at Progress focused on NativeScript, a modern cross-platform solution for building native mobile apps with JavaScript. Todd is an author and frequent speaker on web and mobile app development. Follow Todd @toddanglin for his latest writings and industry insights.