100

I have a div which, when my page is first loaded, is about 100px from the top (it holds some buttons etc. for the page).

When a user scrolls past it, I would like the div to "follow" the user in that it attaches to the top of the screen. When the user returns to the top of the page, I want it back in its original position.

Visualization - xxxxx is the div:

Default (page load)          User vertically scrolled well past it
---------                    ---------
|       |                    |xxxxxxx| < after div reaches top of screen when
|xxxxxxx|                    |       |   page is scrolled vertically, it stays
|       |                    |       |   there
---------                    ---------
Alex
  • 75,813
  • 86
  • 255
  • 348

4 Answers4

147

The trick is that you have to set it as position:fixed, but only after the user has scrolled past it.

This is done with something like this, attaching a handler to the window.scroll event

   // Cache selectors outside callback for performance. 
   var $window = $(window),
       $stickyEl = $('#the-sticky-div'),
       elTop = $stickyEl.offset().top;

   $window.scroll(function() {
        $stickyEl.toggleClass('sticky', $window.scrollTop() > elTop);
    });

This simply adds a sticky CSS class when the page has scrolled past it, and removes the class when it's back up.

And the CSS class looks like this

  #the-sticky-div.sticky {
     position: fixed;
     top: 0;
  }

EDIT- Modified code to cache jQuery objects, faster now.

adamJLev
  • 13,713
  • 11
  • 60
  • 65
  • Were you using a complicated jquery selector to get the element? That could be causing the flickering. Anyhow caching it in a var is a good idea. – adamJLev May 25 '10 at 22:53
  • 1
    Or alternatively instead of appending a div you could just adjust the `margin-top` of the element that's jumping around to match the FIXED div's height.. e.g. `$stickyEl.next().css('margin-top', $stickyEl.height())` – adamJLev May 25 '10 at 22:58
  • This answer is so much better than the accepted answer in the "duplicate question" link. That solution requires you to have a fixed offset (200px in the example), whereas your solution is easily adaptable to a responsive design layout. Thanks! – Jason May 28 '15 at 15:23
  • To scroll down seamlessly when div sticks (without remaining content jumping up) I added an empty div `#replaceDiv` just before the sticking div, which at stick event replaces the exact height of the sticking div. To the `var $window` declaration I added `$replaceEl = $('#replaceDiv'),` and to the `$window.scroll` function I added `$replaceEl.toggleClass('height48', $window.scrollTop() > elTop);`. In my styles.css file I created a class `.height48 { height: 48px; }`, using 48px height since this is the exact height of my div that sticks to the top. Voila! – Marcus Edensky Sep 06 '15 at 18:16
  • 2
    For responsive solution of scrolling down seamlessly when div sticks (without remaining content jumping up), adjusting to variable height in different devices of sticking div, I did the following: Add empty div `#replaceDiv` just before the sticking div, which at stick event replaces the exact height of the sticking div. To `$window.scroll` function, check if div is sticking, and if it is, give `#replaceDiv` the same current height of the sticking div: `if ($window.scrollTop() > elTop) $('#replaceDiv').height($('#cartBar').outerHeight()); else $('#replaceDiv').height(0);` – Marcus Edensky Sep 07 '15 at 20:44
  • 1
    The original question did not presuppose usage of jQuery. – vinntec Sep 23 '15 at 23:49
  • @vinntec is there a reason why someone would be totally against using JQuery these days? I'd imagine sometimes people might not know about JQuery, enough about it to realize its benefits or forgot to tag it. I see a lot of these style corrections lately, but unless someone specifically says I cannot use JQuery I think it's an unnecessary criticism, as this question and answer has clearly helped many people. To the author of this response. Thank you very much. This saved me a lot of research and reading trying to figure this out. Very thankful. – eaglei22 Mar 30 '17 at 16:11
  • @eaglei22: I avoid jQuery these days when a combination of lodash, React (or their equivalents) with ES6 and a transpiler does the job – wolfyuk Apr 05 '17 at 10:46
  • How can this be modified to apply/remove the `sticky` class for example 50px from the top of the screen? – bskool Sep 25 '17 at 09:07
  • Among the best solutions to this common problem. Excellent code. – GlennFriesen Feb 01 '18 at 22:09
23

The trick to make infinity's answer work without the flickering is to put the scroll-check on another div then the one you want to have fixed.

Derived from the code viixii.com uses I ended up using this:

function sticky_relocate() {
    var window_top = $(window).scrollTop();
    var div_top = $('#sticky-anchor').offset().top;
    if (window_top > div_top)
        $('#sticky-element').addClass('sticky');
    else
        $('#sticky-element').removeClass('sticky');
}

$(function() {
    $(window).scroll(sticky_relocate);
    sticky_relocate();
});

This way the function is only called once the sticky-anchor is reached and thus won't be removing and adding the '.sticky' class on every scroll event.

Now it adds the sticky class when the sticky-anchor reaches the top and removes it once the sticky-anchor return into view.

Just place an empty div with a class acting like an anchor just above the element you want to have fixed.

Like so:

<div id="sticky-anchor"></div>
<div id="sticky-element">Your sticky content</div>

All credit for the code goes to viixii.com

germ13
  • 532
  • 1
  • 5
  • 12
Rafvs
  • 231
  • 2
  • 4
2

There was a previous question today (no answers) that gave a good example of this functionality. You can check the relevant source code for specifics (search for "toolbar"), but basically they use a combination of webdestroya's solution and a bit of JavaScript:

  1. Page loads and element is position: static
  2. On scroll, the position is measured, and if the element is position: static and it's off the page then the element is flipped to position: fixed.

I'd recommend checking the aforementioned source code though, because they do handle some "gotchas" that you might not immediately think of, such as adjusting scroll position when clicking on anchor links.

Community
  • 1
  • 1
Andrew
  • 1,187
  • 7
  • 8
0

Use position:fixed; and set the top:0;left:0;right:0;height:100px; and you should be able to have it "stick" to the top of the page.

<div style="position:fixed;top:0;left:0;right:0;height:100px;">Some buttons</div>
Mitch Dempsey
  • 38,725
  • 6
  • 68
  • 74
  • Disagree webdestroya, I don't see much "lag/catchup" in the example I gave in my answer, at least across IE7/8, FFox 3.6, Safari 4, and Chrome on a XP PC. http://perldoc.perl.org/perl.html – Andrew May 25 '10 at 19:50
  • 1
    This doesn't answer the question. The whole point is to not have it fixed under certain circumstances Ex. When at top of the page, 100px from top. Then fixed, once the user scrolls down past it. This just keeps it fixed the whole time. – David Hobs Sep 13 '12 at 04:57