Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery offset top wrong value, but gets right on page resize

I want to achieve a sticky menu like the left navigation on this page: http://getbootstrap.com/2.3.2/scaffolding.html.

My menu is a nav element with position:relative (I tried static as well) that goes fixed when it reaches the top of the viewport.

here's my function:

$(document).ready(function() {
    function stickyNav() {
        var elementPosition = $('nav').offset();
        console.log(elementPosition);

        $(window).scroll(function(){
            if($(window).scrollTop() > elementPosition.top){
                $('nav').addClass("sticky");
            } else {
                $('nav').removeClass("sticky");
            }
        });
    }
    stickyNav();
}); //document ready

the console.log(elementPosition); returns an offset top of around 1200px on page load, which is wrong. But if i resize the page, the value changes to around 650px which is the correct offset top and the function does what it is supposed to be doing.

I've looked around and found out that offsetp top maybe wrong when it's on hidden elements, or it has issues with margins but I actually don't have any complex structure here, just a single visible nav element .

any help on figuring this out would be much appreciated! thanks!!

like image 568
valerio0999 Avatar asked Oct 30 '22 00:10

valerio0999


1 Answers

jQuery(document).ready handler occurs when the DOM is ready. Not when the page is fully rendered.

https://api.jquery.com/ready/

When using scripts that rely on the value of CSS style properties, it's important to reference external stylesheets or embed style elements before referencing the scripts.

In cases where code relies on loaded assets (for example, if the dimensions of an image are required), the code should be placed in a handler for the load event instead.

So if you're using stylesheets that are loaded AFTER the script in question, or the layout of the page depends on image sizes, or other content, the ready event will be hit when the page is not in its final rendering state.

You can fix that by:

  1. Making sure you include all stylesheets before the script
  2. Making sure the CSS is more robust, and doesn't depend that much on content size (such as images)
  3. Or, you can do this on window load event.

Edit:

If you want to make your script dependent on more than one async event (like the loadCSS library), use this:

var docReady = jQuery.Deferred();
var stylesheet = loadCSS( "path/to/mystylesheet.css" );
var cssReady = jQuery.Deferred();
onloadCSS( stylesheet, function() {
    cssReady.resolve();
});
jQuery(document).ready(function($) {
    docReady.resolve($);
});
jQuery.when(docReady, cssReady).then(function($) {
    //define stickyNav

    stickyNav();
});
like image 69
Alex Avatar answered Nov 09 '22 11:11

Alex