Noel De Martin
Noel De Martin

Reputation: 2857

$(document).ready() fires too early

So, I need to know the width of an element with javascript, the problem I have is that the function fires too early and the width changes when the css is tottally applied. As I understood, the $(document).ready() function was fired when the document is completed, but it doesn't seem to work like that.

Anyways, I'm sure that with the code my problem will be understood (this is a simplified example):

<html>
<head>
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <link href='http://fonts.googleapis.com/css?family=Parisienne' rel='stylesheet' type='text/css'>

    <style type="text/css">
        #target {
            font-family: 'Parisienne', cursive;
            float: left;
        }
    </style>
</head>
<body>
    <div id="target">Element</div>
</body>
</html>

<script type="text/javascript">
    $(document).ready(function(){
        console.debug($('#target').outerWidth());
        alert('hold on');
        console.debug($('#target').outerWidth());
    });
</script>

I want to know the width of the #target div, the problem is that the code that's executed before the alert gives a different output than the one after, presumably because the font is not fully loaded and it's measuring the div with the default font.

It works as I expect in Google Chrome, but it doesn't on IE and Firefox.

Upvotes: 36

Views: 34919

Answers (7)

Mira Weller
Mira Weller

Reputation: 2432

If you rely on external content to be already loaded (e.g. images, fonts), you need to use the window.load event

$(window).on("load", function() {
    // code here
});

The behaviour of these events is described in this article:

There is [a] ready-state however known as DOM-ready. This is when the browser has actually constructed the page but still may need to grab a few images or flash files.

Edit: changed syntax to also work with jQuery 3.0, as noted by Alex H

Upvotes: 73

Sparky
Sparky

Reputation: 98738

Quote OP:

"As I understood, the $(document).ready() function was fired when the document is completed,"

$(document).ready() fires when the DOM ("document object model") is fully loaded and ready to be manipulated. The DOM is not the same as the "document".

W3C - DOM Frequently Asked Questions

You can try $(window).load() function instead...

$(window).load(function() {
    // your code
});

It will wait for all the page's assets (like images and fonts, etc.) to fully load before firing.

Upvotes: 12

Brad Parks
Brad Parks

Reputation: 72001

The problem $(document).ready() fires too early can happen sometimes because you've declared the jQuery onReady function improperly.

If having problems, make sure your function is declared exactly like so:

 $(document).ready(function() 
 {
   // put your code here for what you want to do when the page loads.
 });

For example, if you've forgotten the anonymous function part, the code will still run, but it will run "out of order".

console.log('1');
$(document).ready()
{
  console.log('3');
}
console.log('2');

this will output

1
3
2

Upvotes: 1

jeesty
jeesty

Reputation: 1204

I have absolutely, repeatably seen the same problem in IE9 and IE10. The jquery ready() call fires and one of my <div>'s does not exist. If I detect that and then call again after a brief timeout() it works fine.

My solution, just to be safe, was two-fold:

  1. Append a <script>window.fullyLoaded = true;</script> at the end of the document then check for that variable in the ready() callback, AND

  2. Check if $('#lastElementInTheDocument').length > 0

Yes, I recognize that these are nasty hacks. However, when ready() isn't working as expected some kind of work-around is needed!

As an aside, the "correct" solution probably involves setting $.holdReady in the header, and clearing it at the end of the document. But of course, the really-correct solution is for ready() to work.

Upvotes: 1

Didier Ghys
Didier Ghys

Reputation: 30666

The "ready" event fires when the DOM is loaded which means when it is possible to safely work with the markup.

To wait for all assets to be loaded (css, images, external javascript...), you'd rather use the load event.

$(window).load(function() {
    ...
});

Upvotes: 4

gilly3
gilly3

Reputation: 91497

You could use $(window).load(), but that will wait for all resources (eg, images, etc). If you only want to wait for the font to be loaded, you could try something like this:

<script type="text/javascript"> 
    var isFontLoaded = false;
    var isDocumentReady = false;
    $("link[href*=fonts.googleapis.com]").load(function () {
        isFontLoaded = true;
        if (isDocumentReady) {
            init();
        }
    });
    $(document).ready(function () {
        isDocumentReady = true;
        if (isFontLoaded) {
            init();
        }
    });
    function init () {
        // do something with $('#target').outerWidth()
    }
</script> 

Disclaimer: I'm not totally sure this will work. The <link> onload event may fire as soon as the stylesheet is parsed, but before its external resources have been downloaded. Maybe you could add a hidden <img src="fontFile.eot" /> and put your onload handler on the image instead.

Upvotes: 2

Jay
Jay

Reputation: 2141

The jQuery .ready() function fires as soon as the DOM is complete. That doesn't mean that all assets (like images, CSS etc) have been loaded at that moment and hence the size of elements are subject to change.

Use $(window).load() if you need the size of an element.

Upvotes: 5

Related Questions