Reputation: 2217
I have a pretty heavy HTML/jQuery page. Timeline shows an average loading time of 1.5s, so I have decided to show a preloader.
I implement it this way :
HTML just after the <body>
:
<div id="loader-wrapper">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
</div>
And then at the begining of my js file:
$(document).ready(function() {
$('body').addClass('loaded');
$('h1').css('color','#74777b');
});
The "loaded" class allows me to trigger the disappearing of the loader as loading of the page is done.
The problem here is that before my loader covers the screen, I can see for approx half a second the html frame of the website starting to build. How can I make sure that the first thing displayed will be my loader div ?
(sorry but I can't give link or jsfiddle of the project)
UPDATE : To be more specific, the loader works perfectly, but it doesn't start first. Let's say that the total loading time is 2s, the loader will only load on the last 1s. The browser is always building the DOM before displaying the loader.
UPDATE2 : I have tried with a loader without animation, just made of simple div covering the whole screen and with "Loading" as text and I still have the same issue, here is a screen capture of what I can see before the loader appears('please note that the body pic is quite heavy as it is made of 4 layers of different colors stacked through a z-index setting')
Upvotes: 2
Views: 4496
Reputation: 1641
So, what is the root cause of this issue? That's that JavaScript is single-threaded. There's a main thread that's continuously running, and it is simply taking a long time to complete the rendering. This can cause freezing of the browser and squirrelly loading divs.
With asynchronous calls, JavaScript can mimic multithreading and address the root cause. The main thread keeps spinning, doing its work, and the asynchronous task can, on the side, with no performance hit, invisibly populate a hidden div, with each spin/run of the main JavaScript thread. Once the asynchronous task completes, a callback function can be called to hide your preloader div and make the formerly empty div with the main content, visible.
So - one approach to this would be to have the preloading div by itself in a simple page. It will load fast and clean and immediately. Have an empty div below it, which will hold the big, complex content, populated by an ajax call, which is asynchronous. Then, on the DOMContentLoaded event of the simple page, make an ajax call to bring down the rest of the page and load that in the empty div. Takes one line to set a "global" event listener for the built-in DOMContentLoaded event: https://developer.mozilla.org/en-US/docs/Web/Events/DOMContentLoaded
If you want to buy yourself even more time, you could get a timer (with setTimeout() or setInterval()) and give yourself a few more seconds after the ajax call completes, to guarantee everything is completely loaded and ready to display. See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout
FYI, here's a discussion on JavaScript's threading model: https://medium.com/@francesco_rizzi/javascript-main-thread-dissected-43c85fce7e23
See also here for a thread discussion: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop
Upvotes: 2
Reputation: 48826
Put your preloader at the top of your document using inline styles. It will get loaded more quickly.
You should put this in your header
and not actually directly inline, but here's an example of what I mean that doesn't rely on external resources.
eg.
<div id="loader-wrapper" style="width: 100%; z-index: 99998;
position: fixed; top: 0; left: 0; right: 0; bottom: 0; height: 100%;
background-color: #fff;">
<div id="loader"></div>
<div class="loader-section section-left"></div>
<div class="loader-section section-right"></div>
<div>
This will hide everything as soon as the page renders.
You could also hide everything else on the page by default, and then show it when you turn off the preloader.
Upvotes: 1
Reputation: 29337
body
(let's call it .loader
)display:none
to all the direct children of the body but not the .loader
as long as the body is not .loaded
yet..loaded
class when the page is ready then all the children will be shown and the .loader
will be hidden.And the code:
$(function() {
// simulate the heavy page loading
setTimeout(function() {
$('body').addClass('loaded');
}, 1500);
});
body:not(.loaded) > *:not(.loader) {
display:none;
}
body.loaded .loader {
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- put it at the top of the body tag -->
<div class="loader">Loading</div>
<div class="entire_content">
Lorem Ispum Lorem Ispum Lorem Ispum Lorem Ispum Lorem Ispum Lorem Ispum Lorem Ispum Lorem Ispum
</div>
Upvotes: 0
Reputation: 56
You can do the following:
By default, set the style= display:none to the div that contains the HTML content of the page, leaving the loader HTML This will hide the contents of the content on load.
Using jquery document onload, show the loader, and at the close of the loader activity, change the style of the div, to display:inline or display:block
Hope this helps
Upvotes: 0