Question

I'm adding a few new features into a friend of mines website, which is already built. He wants a a div, which is a little bit bellow the header, to be locked to the screen as soon a the user scrolls to the top of it. I created the function bellow which works just fine, but as soon as jquery places the element in a fixed position, all of the elements bellow it slide up causing the entire site to "jump". Is there a way to prevent this from happening without placing all of these elements in an absolute position? This website is pretty involved and will take a lot to redo all of these elements.

jQuery(function($) {
    function lockelem() {

        if ($(window).scrollTop() > 786) 
          $('.tabs').css({'z-index': '10000', 'position': 'fixed', 'top': '-200px', 'width': '100%'}); 
        else
          $('.tabs').css({'position': 'relative', 'top': 'auto'});
        }

   $(window).scroll(lockelem);
   lockelem();
});

Any suggestions would be greatly appreciated!

Was it helpful?

Solution

The previous answer is almost correct. It won't quite work because the else statement won't hide the placeholder div in time. You need this:

function lockelem() {
    if ($(window).scrollTop() > $('#tabs').position().top ) {
          $('#tabs').css({'z-index': '10000', 'position': 'fixed', 'top': '0', 'width': '100%'});
        $("#tabPlaceholder").show();
    }
    if ($(window).scrollTop() < $('#tabPlaceholder').position().top ) {
          $('#tabs').css({'position': 'relative', 'top': 'auto'});
          $('#tabPlaceholder').hide();
    }   
}
lockelem();
$(window).scroll(lockelem);

Working fiddle, you may need to resize the window to make it small enough to show it working: http://jsfiddle.net/rlouie/j7hsX/

OTHER TIPS

I had the same issue with my site. The easiest solution I found was to just create a "spacer" div directly before it.

When the main div is in flow (position:static/relative) the spacer div is hidden. Once the main div comes out of flow (fixed) I show the spacer div. Here's some code:

jQuery(function($) {
function lockelem() {

    if ($(window).scrollTop() > 786) 
      $('.tabs').css({'z-index': '10000', 'position': 'fixed', 'top': '-200px', 'width': '100%'}); 
      //Here we show the Spacer and set its height (just in case you don't know the height of the div before runtime
      $('.tabsSpacer').css({height:$('.tabsSpacer').next().height()+'px'}).show();
    else
      $('.tabs').css({'position': 'relative', 'top': 'auto'});
      //hide the spacer
      $('.tabsSpacer').hide();
    }

   $(window).scroll(lockelem);
   lockelem();
});

If you don't feel like giving it its own class or whatever you can just refer to it as the element directly before the main div with .prev(). The actual implementation is up to you, but that's the general solution I found.

Without knowing what your actual html structure is, it might look something like this:

<div class="tabsSpacer" style="display:none;"></div>
<div class="tabs">...</div>

Elements with absolute or fixed position always get removed from the document flow, which is causing the jump. I find that the most reliable way to account for that is to duplicate the element and use the duplicate as your fixed header. This is better than using a spacer or adding extra padding somewhere or anything that has a potential to be off even a little. This way there's no chance of your original content moving at all, since you never really touch the original content.

As an aside, I also find that keeping the styles in the CSS and just having JS add or remove classes is a much cleaner way to manipulate things. It's saved me a ton of headaches.

You can see a generic example of a sticky header here: http://jsfiddle.net/8SB5Z/

For your code, I'd do this:

JS

jQuery(function($) {

   // Clone the header
   $('.tabs').clone().addClass('clone').insertAfter('.tabs');

   // Add or remove the 'visible' class on the clone as needed
   function lockelem() {
       if ( $(window).scrollTop() > 786 ) {
          $('.tabs.clone').addClass('visible');
       } else {
          $('.tabs.clone').removeClass('visible');
       }
   }

   // Check the positioning on scroll
   $(window).scroll(lockelem);
   lockelem();
});

CSS

.tabs.clone {
   z-index: 10000;
   position: fixed;
   top: 0;
   width: 100%;
   display:none;
}
.tabs.clone.visible {
   display:block;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top