13

I have a sticky header on a site. But when there is a very specific amount of content below the bottom of the viewport (approximately equal to 2-3x padding-top on my html) the scroll oscillates up and down if one tries to scroll slowly. It works well if there is a large amount of content below the page.

EDIT: Sorry if my original question was insufficiently clear, but I want the entire page to scroll until the 'header' reaches the top of the screen, and then (and only then) have the header stop scrolling while the remainder of the page's content continues to scroll behind it.

Here's a JSfiddle

$(function () {
    // Check the initial Poistion of the Sticky Header
    var stickyHeaderTop = $('#stickyheader').offset().top;

    $(window).scroll(function () {
        if ($(window).scrollTop() > stickyHeaderTop) {
            $('#stickyheader').css({
                position: 'fixed',
                top: '0px'
            });
            $('#othercontent').css('margin-top', $('#stickyheader').outerHeight(true));
        } else {
            $('#stickyheader').css({
                position: 'static',
                top: '0px'
            });
            $('#othercontent').css('margin-top', '0px');
        }
    });
});
body {
    font: 13px sans-serif;
    padding-top: 20px;
}
#stickyheader {
    width: 100%;
    height: 40px;
    background:black;
    color:white;
    margin-bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="stickyheader">Sticky header</div>
<div id="othercontent">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
Erik Johnson
  • 858
  • 1
  • 7
  • 29
  • seems broken to me ↑ – MightyPork Jan 14 '15 at 17:46
  • He was missing jQuery and a `
    ` element... should work now.
    – Wex Jan 14 '15 at 18:11
  • I'm going to give this a bump... It's gotta be something simple, I just can't see it – Erik Johnson Jan 26 '15 at 23:23
  • I can't seem to reproduce the oscillation mentioned. In which browser are you seeing this? Also, this question has some other approaches to the same effect http://stackoverflow.com/questions/5902822/stopping-fixed-position-scrolling-at-a-certain-point/5903087#5903087 – James Montagne Feb 04 '15 at 19:45
  • @JamesMontagne I'm seeing this right now on Firefox 35 running on OSX 10.9, as well as other browsers. Did you try the "Run Code Snippet"? It often doesn't show up on the JSFiddle due to differing screen sizes. – Erik Johnson Feb 04 '15 at 19:48
  • @ErikJohnson I'm on Firefox 31 on Linux and can't see what you're talking about, either – Izkata Feb 04 '15 at 19:53
  • @izkata I have updated the code in the question to make the issue more pronounced on my machines, can you try the Run Code Snippet again? – Erik Johnson Feb 04 '15 at 19:58
  • @ErikJohnson Are you talking about the _width_ of the header suddenly reaching the right side of the container? That's the only weirdness I can see. There's still no jumping vertically – Izkata Feb 04 '15 at 20:19
  • @izkata Nope, I did notice that as well though. If it seems like some people can see it and some can't, I'll try and post a screencast of it somewhere later – Erik Johnson Feb 04 '15 at 20:20

2 Answers2

10

You are checking if ($(window).scrollTop() > stickyHeaderTop), which allows the header to scroll one pixel up above the screen before running your code to update the CSS, and then the CSS pushes it down.

Also, you are running calculations based on the element that you are modifying, resulting in the jittering. Set your calculated margin first, then perform your edits on the #stickyheader element:

$(function () {
    var stickyHeaderTop = $('#stickyheader').offset().top;

    $(window).scroll(function () {
        if ($(window).scrollTop() >= stickyHeaderTop) { // <-- Notice the greater than or equals to.
            $('#othercontent').css('margin-top', $('#stickyheader').outerHeight(true)); // <-- This has to be before the #stickyheader changes.
            $('#stickyheader').css({
                position: 'fixed',
                top: '0px'
            });
        } else {
            $('#stickyheader').css({
                position: 'static',
                top: '0px'
            });
            $('#othercontent').css('margin-top', '0px');
        }
    });
});

$(function () {
    var stickyHeaderTop = $('#stickyheader').offset().top;

    $(window).scroll(function () {
        if ($(window).scrollTop() >= stickyHeaderTop) {
            $('#othercontent').css('margin-top', $('#stickyheader').outerHeight(true));
            $('#stickyheader').css({
                position: 'fixed',
                top: '0px'
            });
        } else {
            $('#stickyheader').css({
                position: 'static',
                top: '0px'
            });
            $('#othercontent').css('margin-top', '0px');
        }
    });
});
body {
    font: 13px sans-serif;
    padding-top: 20px;
}
#stickyheader {
    width: 100%;
    height: 40px;
    background:black;
    color:white;
    margin-bottom: 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="stickyheader">Sticky header</div>
<div id="othercontent">
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
</div>
ryebread
  • 984
  • 9
  • 30
  • Unfortunately, that doesn't fix it... Sounded good in theory though :) – Erik Johnson Feb 04 '15 at 20:17
  • Can you make a little LICECap gif snippet to illustrate what you are experiencing? The above code fixes the oscillation on my browser. (Safari 8.0.3) – ryebread Feb 04 '15 at 20:21
  • Interesting! Ok, I'll give that a shot – Erik Johnson Feb 04 '15 at 20:22
  • Nevermind... I was seeing something different. I see what you mean now. Hang on, I will make some more changes. – ryebread Feb 04 '15 at 20:27
  • 1
    @ErikJohnson, ok, I updated the answer to fix your jitter issue. You were running your margin calculations based on an element that you were changing. This lead to the jitter loop. – ryebread Feb 04 '15 at 20:41
  • @ErikJohnson Now that ryebread has identified the issue, another approach to fixing it would be to make your header absolute instead of static initially. In this way the margin of the other content would be static and would not need to change in the if/else. I still can't reproduce the issue so I can't test that but based on ryebread's description of the problem it should work as well. – James Montagne Feb 04 '15 at 21:13
0

I'm not sure why you have written a function to manage the scroll behavior when you can just use some html and css to achieve what you need.

Updated fiddle

body {
  font: 13px sans-serif;
  margin: 0px; <!-- container margin removed to prevent content appearing above -->
}
#stickyheader {
  width: 100%;
  height: 40px;
  background: black;
  color: white;
  position: fixed; <!-- add position fixed -->
  top: 0px; <!-- stick it to the top -->
}
#othercontent {
  padding-top: 50px; <!-- added to offset header -->
}
<div id="stickyheader">Sticky header</div>
<div id="othercontent">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure
    dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.</p>
</div>

If you have any further issues, this tutorail provides all of the basic information required:

Creating Fixed Headers with CSS

Tanner
  • 22,205
  • 9
  • 65
  • 83
  • 3
    The difference is that doesn't have any top padding - the client wants the padding and other things such as a search bar to scroll up and out of the way, leaving only the header – Erik Johnson Feb 04 '15 at 15:08
  • @ErikJohnson sorry, but you never stated that as a requirement in the question, I just showed you an option of how it could be done without code. – Tanner Feb 05 '15 at 11:45