Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Stick header on scroll

I have made a rediculasly small snippet to make a sub-header stick to the top. But since , Like I said - I am by no means a js genious or jQuery genious - and actually far from it - I have my doubts about my own coding abilities..

  • the demo is here : http://jsfiddle.net/obmerk99/VvKq3/1/

The questions :

  • 1 - there seems to be a lot of plugins (and a lot of questions also in this very site) with much more code than my snippet - what am i missing ?? What am I doing wrong ?
  • 2 - will this work cross-browser ?
  • 3 .. and this is a small problem, how to avoid the small "jump" that occurs ? (if you go to the fiddle, and scroll slowly - you will see that the main div "jumps" when the script is evoked .. I have tried to add another .pad class to the lower divs -

added class : .pad when script evoked.

.pad{padding-top:42px;}

but it does not seems to work right : http://jsfiddle.net/obmerk99/VvKq3/2/

  • 5 .How can I calculate the real position of the div ? when I try something like this :
var top = jQuery(window).scrollTop();

var div_top =  jQuery('#header_stick').offset().top;

if (top > div_top) // height of float header;

it is jumpy ... http://jsfiddle.net/obmerk99/VvKq3/4/

  • 6 any other suggestions are welcome..
like image 692
Obmerk Kronen Avatar asked Mar 26 '12 10:03

Obmerk Kronen


2 Answers

The "jumping" occurs because the element was occupying space in the parent element, and when you change its position to fixed it's suddenly not anymore. I don't know the best way to handle it, but one option would be adding a small span (maybe with a single space) just before your #header_stick, with the same height of it, so when it's class is changed there will still be something there to account for the height difference. (Update: your pad solution is probably the best one, once done right; see below)

Your padding solution might also work, provided that: 1) you remember to remove that class when the user scrolls to the top (in your fiddle I see you adding it, but don't see you removing it); 2) You get the height right - I still couldn't look closely to your code, so I don't know where you got wrong. (Edit: the problem was that your .pad class was using the height of the floating header, not the stick header - fixing that and removing the class yielded what I believe to be the correct result)

About the real position of the div, have you tried subtracting the div's offset from the offset of the parent element? This way you'll have its position relative to the parent (pay attention to things like borders, though - I've recently answered another question where details like this mattered).

Update: your problem here seems to be that, when the position is changed to fixed, the offset also varies wildly. I'd suggest calculating the correct height, once, then storing it somewhere so the scroll function can use it. In other words, don't calculate it while scrolling, that makes it much more difficult to find the right theshold to do the class switch.

Other than that, I think you're code is fine, and I believe it will work cross browsers too (at least standards compliant ones; can't say anything about old versions of IE). Very insightful too, I always wondered how this "trick" worked, now I see it's simpler than I imagined...

like image 121
mgibsonbr Avatar answered Sep 21 '22 12:09

mgibsonbr


You can try this way. I made a shorter version for easier analysis. fiddle here

<div id="ontop">floating heading</div>
<header>sticky heading</header>
<div id="wrapper"> 
    1<br/>2<br/>3<br/>4<br/>5<br/>6<br/>7<br/>8<br/>9<br/>10<br/>
</div>



#ontop {width:100%; height:80px; background-color:yellow;}
header {width:100%; height:20px; background-color:lightgrey; }
#wrapper {background-color:lightblue; height:5000px;}

.navfixed {position: fixed; top: 0px; z-index: 100; width:100%; display:block; margin-bottom:120px; } 
.wrapperBelow{margin-top:22px;}


$(function () {
    var elem = $('header'),
        wrapperElem = $('#wrapper'),
        elemTop = elem.offset().top;
    $(window).scroll(function () {
        elem.toggleClass('navfixed', $(window).scrollTop() > elemTop);
         wrapperElem.toggleClass('wrapperBelow', $(window).scrollTop() > elemTop);
    }).scroll();
});
like image 31
Piotr Ciszewski Avatar answered Sep 25 '22 12:09

Piotr Ciszewski