Skip to main content

Is $(document).ready() also CSS ready?



I've got a script executing on $(document).ready() that's supposed to vertically align block element in my layout. 90% of the time, it works without issue. However, for that extra 10% one of two things happens:









  • There's an obvious lag in the time it takes to do the centering, and the block elements jump into position. This could simply be performance related - as the page size is often large and there is a fair amount of javascript that is executing at once.









  • The centering will completely mess up, and the block element will either pushed down too far or not far enough. It appears as if it tried to calculate the height, but was getting improper measurements.









Is there any reason why executing a script on DOM-ready would not have all the correct CSS values injected into the DOM yet? (all CSS is in the <head> via a <link> ).





Also, here's the script that's causing the issue (yes, it's been taken straight from here ):







(function ($) {

// VERTICALLY ALIGN FUNCTION

$.fn.vAlign = function() {

return this.each(function(i) {

var ah = $(this).height();

var ph = $(this).parent().height();

var mh = (ph - ah) / 2;

$(this).css('margin-top', mh);

});

};

})(jQuery);







Thanks.



Source: Tips4all

Comments

  1. From the 1.3 release notes:


    The ready() method no longer tries to make any guarantees about waiting for all stylesheets to be loaded. Instead all CSS files should be included before the scripts on the page. More Information


    From the ready(fn) documentation:


    Note: Please make sure that all stylesheets are included before your scripts (especially those that call the ready function). Doing so will make sure that all element properties are correctly defined before jQuery code begins executing. Failure to do this will cause sporadic problems, especially on WebKit-based browsers such as Safari.


    Note that the above is not even about actually rendering the CSS, so you may still see the screen change when ready() kicks in. But it should save you from problems.

    Actually, I find it a bit strange that just putting the CSS above the JS will solve all issues. The CSS is loaded asynchronously, so JS loading can start and finish while the CSS is still being downloaded. So if the above is a solution, then executing any JS code is then halted until all earlier requests have completed?

    I did some testing, and indeed, sometimes JS is delayed until the CSS is loaded. I don't know why, because the waterfall shows that the JS has completed loading long before downloading the CSS has finished.

    See JS Bin for some HTML and its results (this has a 10 second delay), and see webpagetest.org for its waterfall results. This uses some script from Steve Souders' cuzillion.com to mimic slow responses. In the waterfall, the reference to resource.cgi is the CSS. So, in Internet Explorer, the first external JS starts to load right after the CSS was requested (but that CSS will take another 10 seconds to finish). But the second <script> tag is not executed until the CSS has finished loading as well:

    <link rel="stylesheet" type="text/css" href=".../a script that delays.cgi" />

    <script type="text/javascript" src=".../jquery.min.js"></script>

    <script type="text/javascript">
    alert("start after the CSS has fully loaded");
    $(document).ready(function() {
    $("p").addClass("sleepcgi");
    alert("ready");
    });
    </script>




    Another test with a second external JS after getting jQuery, shows that the download of the second JS is not started until the CSS has loaded. Here, the first reference to resource.cgi is the CSS, the second the JS:



    Moving the stylesheet below all JS indeed shows that the JS (including the ready function) runs much earlier, but even then the jQuery-applied class --which is yet unknown when the JS runs-- is used correctly in my quick tests in Safari and Firefox. But it makes sense that things like $(this).height() will yield wrong values at that time.

    However, additional testing shows that it is not a generic rule that JS is halted until earlier defined CSS is loaded. There seems to be some combination with using external JS and CSS. I don't know how this works.

    Last notes: as JS Bin includes Google Analytics in each script when running from the bare URL (like jsbin.com/aqeno, the test results are actually changed by JS Bin... It seems that the Output tab on the edit URL such as jsbin.com/aqeno/edit does not include the additional Google Analytics things, and surely yields different results, but that URL is hard to test using webpagetest.org. The reference to Stylesheets Block Downloads in Firefox and JavaScript Execution in IE as given by strager is a good start for a better understanding, but I got many questions left... Also note Steve Souders' IE8 Parallel Script Loading to make things even more complicated. (The waterfalls above are created using IE7.)

    Maybe one should simply believe the release notes and documentation...

    ReplyDelete
  2. The DOM ready fires when all the DOM nodes are available. It has nothing to do with CSS. Try positioning the style before or try loading it differently.

    ReplyDelete
  3. To the best of my knowledge the ready event is fired when the DOM is loaded - which means that all the blocking requests (i.e. JS) have loaded and the DOM tree is completely graphed. The ready state in IE relies on a slower event trigger (document.readyState change vs DOMContentLoaded) than most other browsers so the timing is browser dependant also.

    The existence of non-blocking requests (such as CSS and images) is completely asynchronous and unrelated to the ready state. If you are in a position where you require such resources you need to depend on the good old onload event.

    ReplyDelete

Post a Comment

Popular posts from this blog

Why is this Javascript much *slower* than its jQuery equivalent?

I have a HTML list of about 500 items and a "filter" box above it. I started by using jQuery to filter the list when I typed a letter (timing code added later): $('#filter').keyup( function() { var jqStart = (new Date).getTime(); var search = $(this).val().toLowerCase(); var $list = $('ul.ablist > li'); $list.each( function() { if ( $(this).text().toLowerCase().indexOf(search) === -1 ) $(this).hide(); else $(this).show(); } ); console.log('Time: ' + ((new Date).getTime() - jqStart)); } ); However, there was a couple of seconds delay after typing each letter (particularly the first letter). So I thought it may be slightly quicker if I used plain Javascript (I read recently that jQuery's each function is particularly slow). Here's my JS equivalent: document.getElementById('filter').addEventListener( 'keyup', function () { var jsStart = (new Date).getTime()...

Is it possible to have IF statement in an Echo statement in PHP

Thanks in advance. I did look at the other questions/answers that were similar and didn't find exactly what I was looking for. I'm trying to do this, am I on the right path? echo " <div id='tabs-".$match."'> <textarea id='".$match."' name='".$match."'>". if ($COLUMN_NAME === $match) { echo $FIELD_WITH_COLUMN_NAME; } else { } ."</textarea> <script type='text/javascript'> CKEDITOR.replace( '".$match."' ); </script> </div>"; I am getting the following error message in the browser: Parse error: syntax error, unexpected T_IF Please let me know if this is the right way to go about nesting an IF statement inside an echo. Thank you.