Make a DIV stick when you scroll

I’ve seen this method used a lot around the web and I’ve recently been working on a website where I wanted to incorporate it.  After finding zero results in about a minute of research, I thought this would be a neat topic to write a post about.

So my main concept here is to have a sidebar that would stick to the top of the page once the window was about to pass it by while scrolling. This could be used for dozens of reasons. Perhaps you want to ensure your advertisements are being shown the maximum amount of time possible; or maybe you want to offer your visitors an area of quick-links so they wouldn’t have to scroll to the top of the page to navigate somewhere else.  The site I’m working on is e commerce, so it will be an area to up-sell other products relative to the page the user is viewing.

stick a div when it scrolls

In the code below, I have two DIVs floating that represent the main content area and the sidebar.  Sidebars are usually shorter than the main content area, so this is where my sticky DIV will be.  I give it an id of “sticker” (original, huh?).  With some jQuery, I’m able to fire off a function every time I scroll on the page.  This function calculates my current position, or viewport, or distance from the top.  It also calculates how far from the top my “sticker” div is.  Then, there’s an IF statement that’s fired off…

IF my current position is greater or equal to the “sticker” position, give the sticker div a class of “stick”.  This changes the CSS of the div to have a FIXED position as long as the viewport is lower than the position of the sticker.

HTML – Nothing crazy going on here – a mere 2-column setup

<div id="wrapper">
  <div id="mainContent">
    <!--Content for your main div - like a blog post-->
  </div>
  <div id="sideBar">
    <!--Some content in your right column/sidebar-->
    <div id="sticker">...start scrolling to watch me stick</div>
  </div>
  <div class="clear"></div>
</div>

CSS –  Again, nothing super high-tech – just not the styles applied to div#sticker and the class “.stick”

div#wrapper {
	margin:0 auto;
	width:900px;
	background:#FFF;
}
div#mainContent {
	width:560px;
	padding:20px;
	float:left;
}
div#sideBar {
	width:230px;
	padding:20px;
	margin-left:30px;
	float:left;
}
.clear { 
	clear:both; 
}
div#sticker {
	padding:20px;
	margin:20px 0;
	background:#AAA;
	width:190px;
}
.stick {
	position:fixed;
	top:0px;
}

jQuery – Calculates the position of the sticker div and makes its position fixed if the page has scrolled that far

$(document).ready(function() {
	var s = $("#sticker");
	var pos = s.position();					   
	$(window).scroll(function() {
		var windowpos = $(window).scrollTop();
		s.html("Distance from top:" + pos.top + "<br />Scroll position: " + windowpos);
		if (windowpos >= pos.top) {
			s.addClass("stick");
		} else {
			s.removeClass("stick");	
		}
	});
});

Conclusion - I used to think these sticker DIVs were annoying, but I’m coming across more and more ideas to implement them to help the visitor. I have also thrown a demo page together if you want to see it in action. Download zipped source code

* UPDATE – per David’s request, the sticker stops at the large footer – demo page 2Download zipped source code (2.0)

60 thoughts on “Make a DIV stick when you scroll”

    1. ISSA – it works on the iPad but behaves a little differently. The window position value gets updated once the user stops scrolling with a touch device/tablet. Once the scroll event is complete, the div snaps down to it’s new position in view.

  1. Hey Jonathon

    Great little piece of code.

    I’m having a little issue where I want to wrap the #sticker around the content which I want to scroll down – but when I change the content within the #sticker div, it gets REPLACED when I scroll down (by the Distance from top… text).

    Could you help shed some tips onwhat I could do where the content in the #sticker doesnt change, and scrolls down with the box?
    Thanks

    1. Absolutely Cody. The reason it’s being replaced is because I am changing the html of the box every time it scrolls. I did this just to demonstrate that the DIV sticks once the scroll position is greater or equal to the ‘distance from top’ value. All you have to do is remove the line of code that sets the HTML in the javascript block (toward the top of the page).

      Remove this line:
      s.html("Distance from top:" + pos.top + "<br />Scroll position: " + windowpos);

      That should take care of it. Thanks for pointing that out!

  2. Hi!

    I’m trying to implement the code in wordpress. Where should I save the jquery file? I know that my theme already uses jquery.

    I’m a newbie. Thanks for the code!

    Chetan

    1. Hey Chetan – if your wordpress theme already uses jQuery, all you have to do is copy and paste my javascript block anywhere you’d like. It just has to be placed after the jquery call. One thing you’ll have to do is wrap a script tag around the code block like so:

      <script type="text/javascript">***Add code here***</script>

      Also, make sure you delete line 6 out of the javascript. That’s for the demo’s integer values and you don’t need it. See my response to Cody above.

  3. I tried using this but in case that the sticker is bigger than main text – left is for ex. 10 lines of index, and right is 100 lines of text, soon as I apply this, screen goes berserk. sticker is “trying” to go left… any ideas why this happens…
    ty

    1. Sounds to me it might be a css floating problem. I tried out what you were explaining on the demo zip project attached and couldn’t get it to act that way. Also, make sure you’re commenting (or deleting) the line where I’m setting the html. It’s line 17 if you open the html file.

  4. Nice piece of code – and must simpler than I expected for this effect. It’s working great for what I had in mind, although I just discovered it will also position the sticker div above my site footer when scrolling down.

    Is there a way to add a piece to the javascript where it also detects a fixed distance from the page bottom to discontinue the scrolling effect? I want the div to stay contained within the main content and be visible alongside my articles, but not pop into the lower section of the site.

    Thanks!

    1. Thanks David – I’m all about making it simple. I did exactly what you’re asking for about a year back and I have to track down the code. I’ll reply once I get a chance to track it down.

  5. I modified the if/then statement to also use document.body.clientHeight-XXX (where XXX=height of my footer) to determine a “stopping point” but basically this makes the div disappear once scrolled past that position. Probably just a matter of determining the right way to define that state in CSS.

    1. David – I added a new zipped source file at the bottom of the post. The only thing I changed in the CSS was the addition of the footer element. The rest of the changes are to that main window.scroll function. I added comments to the code so hopefully you can understand what my thinking was. Hope this helps!

  6. Had to change the .stick CSS to be position:absolute, not fixed. Margin being 10px also made things offset kinda bad for me, since my div was going to ride over a table with a fixed width and columns that needed to match up. So I did this:

    <script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js”></script>

    <script type=”text/javascript”>
    $(document).ready(function() {
    var s = $(“#sticker”);
    var pos = s.position();
    $(window).scroll(function() {
    var windowpos = $(window).scrollTop();
    s.css(“top”, windowpos + 150);
    //s.html(“Distance from top:” + pos.top + “<br />Scroll position: ” + windowpos);
    s.html(“<table width=’750′ align=’center’ style=’color:white;font-face:Times;font-weight:bold;text-decoration:underline’><tr><td align=’center’ width=’61%’>Column 1</td><td align=’center’><span style=” width=’10%’>Column 2</td><td align=’center’ width=’29%’>Column 3</td></tr></table>”);
    if (windowpos >= pos.top) {
    s.addClass(“stick”);
    $(“.linebreak”).show();
    } else {
    s.removeClass(“stick”);
    $(“.linebreak”).hide();
    }
    });
    });
    </script>

    <style type=”text/css”>

    div#sticker {
    padding:11px;
    background:#AAA;
    }
    .stick {
    position:absolute;
    z-index:-10;
    color:white;
    }
    </style>

    and added these rows to my table:

    <tr>
    <td colspan=”3″>
    <div id=”sticker” class=”stick”>
    <table width=”780″ style=”text-decoration:underline;color:white;font-weight:bold”>
    <tr>
    <td align=”center” width=”61%”>Column 1</td>
    <td align=”center” width=”10%”>Column 2</td>
    <td align=”center” width=”29%”>Column 3</td>
    </tr>
    </table>
    </div>
    </td>
    </tr>
    <tr><td class=”linebreak”><p> </p></td></tr>
    <tr><td class=”linebreak”><p> </p></td></tr>
    <tr><td class=”linebreak”><p> </p></td></tr>

    Worked really good after all this! Thank you!
    (Mod, please delete my previous comments – code wasn’t correct, thanks!)

  7. Thanks, Jonathan. Here’s another version that worked well, and is even more compact:

    <html><head><title>test scroll</title>
    <script type=”text/javascript” src=”http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js”></script>
    <script type=”text/javascript”>
    $(document).ready(function() {
    $(window).scroll(function() {
    var windowpos = $(window).scrollTop();
    $(“.stick”).css(“top”, windowpos);
    });
    });
    </script></head><body>
    <table border=1>
    <tr><td valign=”top”>
    <div id=”sticker” class=”stick” style=”position:relative;z-index:10;”>
    <table><tr><td>My stuff I want to move</td></tr></table>
    </div>
    </td><td>
    <!– Main Content Here –>
    a<br>b<br>c<br>d<br>e<br>f<br>g<br>h<br>i<br>j<br>k<br>l<br>m<br>n<br>o<br>p<br>
    </td></tr>
    </table>
    </body></html>

  8. Wow this is awesome! It took me a little bit to figure it out because I tried to put the on the master page(.net) in the content holder but you have to put it on the page you want it on in the content holder.

    Anyways this is super simple and thank you so much for sharing the information! :)

  9. Thanks for sharing this simple example! One thing to consider: on line 3 of your JavaScript, you get the position of the target element using jQuery’s .position() function. This caused me to have some trouble because the code was getting activated before I actually scrolled down to the target element on my page.

    As I found in the jQuery docs (http://api.jquery.com/position/), .position() actually returns the coordinates of the element relative to its parent, not its position on the screen. You should probably use .offset() instead, which will provide its coordinates relative to the entire document. I think this is what most people will want when they try to use your code.

  10. Good article, I adapted it to my situation and replaced the addClass with:

    s.css(“margin-top”, ypixels)

    Where:

    var ypixels = (windowpos – 400) + ‘px’;

    Because I wanted my sidebar to start moving when it reached 400 pixels from the top of the page.

    1. Exactly where did you place this code? Im trying to achieve the same thing but cant get your code to work.

    2. Hi Josef, if you download the zipped project and open it up you can see all the code as it was written. You can even use the code as a starter template if you’d like…

    3. Hi Daniel,

      Where exactly in the code do you include these lines? I’m using demo V2 and for some reason i can’t make it work.

      Thanks for your help! Karl

    1. Hey Chris – thanks for the feedback! Check out Daniel’s comment. I think his little snippet could be what you’re looking for if you know exactly how many pixels down you want the div to “stick”. I would recommend getting the height of your header and navigation, adding them together and setting that value in place of “237″ just in case these elements get larger/smaller with modification.

  11. Great solution, works well. Question: Is it also possible to use a 3 column layout and stick the left and the right column?

    At the end i would like to have two sidebars and the content in the middle. I tried to amend the existing code, but the content will be hidden by the left div as soon i start to scroll.

    Thanks

    1. Hey Thanks Daniel – I don’t see why it would work, but you need to do a few things to make the magic happen. Since you have 2 stickers, give them different IDs, like “stickerLeft” and “strickRight” or something like that. Then you’ll need to duplicate the jQuery document.ready function so one is serving the left, and one for the right. Then, you have two event listeners that will run independently. I’m curious to see if you can get this to work.

  12. Hi Jonathan,

    That’s exactly what i did. Duplicated the relevant parts out of the CSS and created a second event of the document.ready function.

    Seems i have to adapt the floatings as well. As mentioned as soon i start to scroll the content moves to the left. If i use the float:right property the content moves to the right. The sticking itself works, so even if the content is at the wrong place both sidebars are moving with the content.

    1. OK, i found a solution to that.

      To prevent the middle container moving below the left sidebar i added a 3rd instance of the document.ready function and added a class for the main container there.

      Within the class i specified that it adds margin-left to it. The value of margin-left needs to equal the size of the left sidebar.

  13. Hi Jonathan,
    Thanks for the nice article.

    I have right sidebar which is bigger than page wrapper, only for some pages.

    I want to display sidebar so that it looks it is inside wrapper. How can I achieve that?

    Best Regards,
    Damodar

    1. Hi Damodar,
      It sounds like your CSS needs a few changes. Do you have a live example I can see? Your “wrapper” is the full width of the page and the “sidebar” should be a fraction of that width so it fits inside and plays nice. Did you view the demo pages? I’m thinking you can view the CSS on those pages and compare to what you have on your own site. Hope that helps.

  14. Hi Jonathan,

    As per you guess it was wrapper’s width.
    Thanks for your help.
    Sorry don’t have demo page working on it.

    Best Regards,
    Damodar

    1. Hi Jonathan,

      I have added a button.
      When it is clicked, adding some text to fixed div or increases height of fixed div.

      I have added stickermax as maincontent div.
      But it is stoping on top of footer.

      function sidebarText() {
      var sidebar = $(“#sticker”);
      sidebar.html(“Your selections Your first selection Your selections last Your selections Your last selections :END!!!”);
      }
      $(document).ready(function() {
      var s = $(“#sticker”);
      var pos = s.position();
      var stickermax = $(“#mainContent”).outerHeight(); //$(document).outerHeight() – $(“#footer”).outerHeight() – s.outerHeight() – 40; //40 value is the total of the top and bottom margin
      $(window).scroll(function() {
      var windowpos = $(window).scrollTop();
      if (windowpos >= pos.top && windowpos = stickermax) {
      s.removeClass(); //un-stick
      s.css({position: “absolute”, top: stickermax + “px”}); //set sticker right above the footer

      } else {
      s.removeClass(); //top of page
      }
      });
      //alert(stickermax); //uncomment to show max sticker postition value on doc.ready
      });

      How to fix this? Working example is in test page (my website).

      Best Regards,
      Damodar

  15. Will it work only for div….

    i have my website code in tables i want to use this for tag please help me….

    is it possible, if yes please tell me…

    Thanks In Advance

    1. I don’t see why it wouldn’t work from within a table cell. The “sticker” container itself must be a div and you can certainly nest it within an HTML table cell. Best of luck.

  16. Its not working

    my code is just like this

    table
    thead
    tr

    th
    th
    th
    th

    /tr
    /thead

    where should i call “sticker” function
    its working outside of the table but in table its not working….

    1. Rodrigo – I changed a few CSS rules the other day and didn’t realize the comments section was still dark. Try refreshing the site now. Thanks for pointing it out.

  17. Very nice piece of code! But i have a question:

    I want to stop the scrolling div at the end of the parent div. But with more content beneath then only a footer. It stops at the beginning of the footer, but i have more content than only the footer.

    Is there someway to stop the div at the bottom of the parent div?

    Thanks in advance!

    1. Hey Bob – you can probably change line 15, where the javascript is calculating the “stickmax” variable.

      Change it to something like:
      var stickermax = $(“#your_div_id”).outerHeight();

      Note: if you have a header/navigation or something above your parent div, you would want to add their heights to the overall stickermax value like so:
      var stickermax = $(“#your_div_id”).outerHeight() + $(“#your_header_id”).outerHeight();

      Hope that helps you out.

  18. Hi bro, how can i make a html element( div, header part etc,) to stick on, instead entering the text on the js portion..

    1. Hey Vish – The content you set inside the sticker div can be any HTML you want. You can be encountering a problem because you didn’t comment out line 6 of the jQuery portion (s.html…..). I added that in there just so you can see why the sticker actually sticks. Does that help?

  19. Thanks Jonathan, the footer part took a couple of my hours on a single line calculation with no success. your stickermax equation did work on my code..

    Thanks David for requesting about the same issue which I was just about request here. :)

  20. WOW good work I like the demo page style, thank you for shearing, I really appreciate your generosity.

  21. Hi there I was wondering if you could remedy a problem I am having with this code? First off, I like it much better than previous code I was trying where it wasn’t working in Chrome for the snap back when you scroll up.

    Only issue with this code is that when it “sticks” it gets pushed off to the right rather than stay where it is. Like, it floats right. I am implementing this code into a WordPress template.

    1. If anything, actually, it would be cool to have to have it float off to the left, covering the entire top of the page since it is a navigation bar. Think that would be possible? I already find this cool that I can add any type of css I want to the stick css so that it looks a little different while it is sticking.

  22. Thanks a bunch for this!!!!

    I tried a number of other ways that I found online but yours is by far the easiest and quickest.

    Awesome Work Sir.

  23. If found if you changed this line:


    var stickermax = $(document).outerHeight() - $("#footer").outerHeight() - s.outerHeight() - 40;

    to:

    var stickermax = $(document).outerHeight() - $("#footer").outerHeight() - s.outerHeight(true);

    You don’t need to hardcode the “stickers” top and bottom margins.

  24. Thanks for sharing this code!

    I am not a jquery expert, but I have simply modified the snippet like this to achieve the effect some of you were talking about:

    $(document).ready(function() {
    var s = $(“#isofilter”);
    var pos = s.offset();
    $(window).scroll(function() {
    var windowpos = $(window).scrollTop();
    if (windowpos >= pos.top – 172) {
    s.addClass(“stick”);
    } else {
    s.removeClass(“stick”);
    }
    });
    });

    where (windowpos >= pos.top – 172) indicates that I need the div to stick to a position 172px below the top of the page (http://www.youngandsmitten.com).

    Is there anything I am overlooking? It appears to work fine for me. Any concerns about browser compatibility, or other issues?

    The only glitch I haven’t managed to get rid of is that the div jumps (if only ever so slightly) just when it ‘docks’ onto the header section. If you have any suggestion about how to make it even smoother, please let me know.

    Best,
    Alex

  25. Hi, thank you for this awesome code! I’m new to jquery and I tried to modify your code to achieve an effect I wanted but failed horribly =\ … I wanted to have a longer sidebar and make the bottom of the sidebar stick to the bottom of the page when scrolling down, and the top of the sidebar stick to top of the page when scrolling up … here’s an illustration to visualize what I’m talking about: http://goo.gl/dxLESE

    I know this was posted a long time ago, but do you think you could help me do this?

  26. Hello..
    My Div has to move slowly when I click a button and next I will click Return button the same Div has to come and set it own place slowly
    Please guide how can I do this

    Thank you

Comments are closed.