William Duffy

Glasgow Based C# ASP.NET Web Developer

Keep element in view while scrolling using jQuery

I’ve just completed an interesting project; an online application form that calculated a quote dynamically using Javascript as the user specified their choices.

=====================================================================
UPDATE APRIL 2011 – Due to the overwhelming feedback on this blog post I have created the jScroll plugin which you can download here. You can also fork and contribute to its development at github. If you use the plugin I’d love to hear from you!
=====================================================================

The quote details where to be displayed to the right of the form, but the form was longer than the height of the page so scrolling was required. In order to keep the quote price visible at all time I needed a way to make the element container reposition itself to remain in view when the user scrolled up and down on the form.

I actually thought the solution would be a single search away on Google, but I couldn’t believe that there was no quick answer available. A few people had suggested a css version using position:fixed, but due to the structure of my css and the fact that I wanted a smooth scrolling effect on the element the css idea just didn’t cut it.

I knew jQuery was going to produce my answer, but nobody seemed to have anything available to tell me how. I ended up writing my own against the jQuery framework, which actually proved extremely easy. Hopefully if your looking for something similar this will meet your needs. You can view the working demo here. Ok, lets get started.

First thing to do is make sure you have the jQuery library included on your page. This is super easy to do. If you haven’t got it yet download the production file (19kb) from www.jquery.com. Then simply include it on your page using a script include in your head section.

<script src="jquery-1.3.2.min.js" type="text/javascript"></script>

Next up, give the element that will be dynamically repositioned an id so that it can be found in the DOM. This again is super easy.

<div id="scrollingDiv"> <--- notice the id tag
       Your content in here
</div>

Now that we have the basics done we need to write the code to reposition the element dynamically using JQuery. This is the technical bit, but I’ll try break it down so it’s easy to understand.

We need to listen out for, and handle, the scroll event. Basically every time the user scrolls their browser window it alerts any code that has registered interest in this event that it has just happened. We will reposition the element when this happens, so this is perfect for us! To do this we use JQuery’s event handling support to attach a function to the window’s scroll event.

$(window).scroll(function() {
       do stuff here...
});

Now that we are being alerted that the scroll event has fired we need to actually do something. The code below does a few things.

  1. jQuery traverses the DOM and returns the element who’s id is scrollingDiv
  2. We call JQuery’s animate function on the returned element and tell it to increase the top margin to the size of the top scroll location (I’ve added 30 to the total because I already have a top margin of 30 on the div. You can remove this if you do not have a top margin already on your div). We also set the animation speed to slow. You can set this to fast, or specify a numerical value in milliseconds if you prefer.
$(window).scroll(function(){
       $("#scrollingDiv")
              .animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "slow" );
});

Because this event can fire many times in a row we need to make sure we stop all previous repositions before progressing with the latest one. Imagine a users scrolls 3-4 times really fast. We want just the last call to be in control of the repositioning. Ensuring that all repositioning is stopped beforehand makes for much faster handling of the event, resulting in smoother animation. We call this BEFORE the code snippet above.

$(window).scroll(function(){
       $("#scrollingDiv")
              .stop()
              .animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "slow" );
});

Our element now scrolls along with the window. There is one area we can still make this a little smoother though. Whenever the scroll event fires jQuery traverses the DOM looking for our element. In order to alleviate this overhead we can simply store the jQuery reference to our element in a variable when the DOM is initialised and reference this instead.

var $scrollingDiv = $("#scrollingDiv");
 
$(window).scroll(function(){
       $scrollingDiv
              .stop()
              .animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "slow" );
});

That’s all there is to it. You now have an element that scrolls smoothly into position so that it remains in view at all times. I’ve tested the code in IE6, IE7 and Firefox 3, every one of which works a treat. The complete code snippet is included below. Enjoy!

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>
<script>
	$().ready(function() {
		var $scrollingDiv = $("#scrollingDiv");
 
		$(window).scroll(function(){			
			$scrollingDiv
				.stop()
				.animate({"marginTop": ($(window).scrollTop() + 30) + "px"}, "slow" );			
		});
	});
</script>

Recommended Reading

I recommend reading the following books to gain a better understanding of the topics discussed in this blog post.


Tagged as , + Categorized as HTML & CSS, jQuery

74 Comments

  1. Hi there.

    Thanks for sharing your knowledge…. jQuery is Simply awesome.

    Regards
    Ibrahim

  2. Excellent piece of code, its excellent for my needs, but the div the scrolls is not in view when the page loads, so when you scroll down the div always stays out of view. I’ve attempted to resolve this by activating the scrolling function when a control has focus, but it still jumps out of view. I’m still playing with it but have not resolved it yet. Any suggestions?

  3. hi again, i resolved the issue by setting a negitive value for the margin top of the div. thanks again for this awesome snip.

  4. @Donald Glad you got it working :)

  5. You just saved me a ton of work! I was about to pull out all the javascript stops and probably end up with a solution with many many more lines.

  6. thanks
    i was just looking for it.

  7. first of all, thank you for sharing this!

    ran into a problem, though:

    i was using jquery 1.2.6 and it worked perfectly, after modifying the code to fit my site of course…but after recently upgrading to 1.3.2, the button (image) doesn’t even move anymore…though I see you’re running jquery 1.3.2 in your example with no problem…

    i haven’t spent much time on this, but wanted to see if anyone else had the same problem.

  8. Cool piece of code here!!

    I would have this scroll feature but the #scrollingDiv may not ran outside his parent. Any idea to fix this?

    Thanks already, Bert

  9. This was exellent! Thanks :)

  10. Thanks for sharing! Exactly what I needed! :)

  11. Thanks Just what I needed!

  12. Hi!

    thnx for sharing you code. Got it working without any problems :)

    Have a question:

    I want to achieve the effect of the menu sliding in and out of the screen when starting from the top of the page.

    I have added 40 to the scrolltop location and in css top:-200px .
    When you enter the page, the menu is not visible ( i.e. outside of the screen).
    The moment you start scrolling downwards, the menu scrolls into the screen.

    What I want to achieve is this: the menu scrolls into the screen after scrolling the page about 200 px down and when scrolled back to the top of the page, the menu should scroll out of the screen again. This is becuase the site i’m making also has a header menu.
    The testsite ( under construction) is http://test.lethal-zone.eu

    I know this can be done, have seen it on a website somewhere, but how to do so in jQuery with your script?

  13. Hi William,

    thanks for the tip. I’ve been looking for something like this for a while now, but with a slight twist. What I need is to have the element scroll normally, but remain at the top of the page when it is supposed to disappear under the fold. See how the table header row works in this page: http://drupal.org/project/issues/search/drupal?version0=7.x&issue_tags=Usability,%20d7ux

    Anyway, I’m just leaving this here in hope someone can chime in with a useful link.

    Thanks again.

  14. Works in Chrome 4.0 on Windows 7. Great.

  15. Hi William

    I’ve just found your snippet and I am putting it into place for one of our clients now :)

    Many thanks

    Darren, UK

  16. Wonderfull, the .stop() make the scrolling div happier than ever!!!

  17. This was just what I was after!

    I wouldn’t mind turning this into a jQuery plugin. If you’re interested, drop me a line.

    Keep up the good work!

  18. Nikhil Owalekar says:

    I had overflows hidden on my website so it wasnt working on chrome… now that I have enabled those, it is working fine..
    I would definitely like this to work even with hidden overflows..
    My website has vertical scrolling .. and I dont want users to be able to scroll wherever they want So I hid the scrollbars… they are ON again :(

  19. Very nice article. Very nicely explained :)
    Thanks a lot William!

  20. Very nice – does anyone know of a MooTools implementation?

  21. Thank you for sharing your knowledge my friend! Do I need to purchase both books or one is enough?
    Thanks dude!

  22. @Eric, No those are just two of the best. Both cover the same areas. My favourite one is Learning JQuery 1.3.

  23. Thanks for this! It was exactly the bit of code that I needed to tweak something for one of my clients :)

  24. Many thanks for the run down for this.. just what I needed and got it working in no time.

    Cheers,
    James

  25. hi,

    what if the div cant’ be floated b/c it needs to be always CENTERED on the page?

    I need to open a div dynamically on the page with one of those overlays with black background and opacity set to < 100% so content of page is partially obscured and div floats on top.. ALWAYS centered on the page..

    I took out float:left for #scrollingDiv and it doesn’t work..

    thank you..

  26. @Maya, remove the float left, set the position to absolute and the z-index to 99. That will render it on its own layer. You can then set the margins position the scrolling element in the centre of the screen if required.

  27. Hi ur code is working superbly , but i had a problem with this when i am scrolling down the div my text is also automatically arranging which is in another div.
    Here my problem when i am moving up my text is rearranging .
    That is also not a problem when i am scrolling down my text is not rearranging like old .
    When i am moving up it is rearranging the text can u help me

  28. @Babapaven, it sounds like the text that is arranging is contained in the same parent div as the scrolling element. As text is an inline element it will wrap around the floating div as it scrolls. To cater for this create a wrapper div which contains the body of text only, you can float it or set it’s width to the required size required. Ensure that the scrolling div is not inside this wrapper. This should sort the issue, good luck.

  29. Hi there,

    The script is great! Thanks for sharing. I was wondering if this is the same as what I see at the bottom of this page? http://c-k.com/cultural-dictionary/ Is there something I can do to tweak your code so that it doesn’t animate?

  30. @Bryan The example you gave uses pure css. If that is what you are trying to recreate you would be better using their pure css method. You can see how they do it in their stylesheet (http://c-k.com/cultural-dictionary/styles/styles.css) on line 402. If you haven’t got it already I’d suggest downloading Firebug for Firefox and using it to assess the html and css setup they are using.

  31. Nice work – really goes to show the power of JQuery with just a few lines of code.

  32. I’ve noticed a bit of a bug with this script, even in your own demo page:
    If you resize the window so it’s smaller than the scrollingDiv, then scroll to the bottom of the page, the scrollingDiv will move down below the bottom. This extends the length of the page slightly, allowing you to scroll further, thereby extending it even more. The result is that with this script on a page, a user with a small window or a user with a small screen resolution (i.e. mobile platforms) will have an endlessly scrollable page.

    How can we stop the div from scrolling past the bottom of the page?

    (I’ve tinkered abit with this, but the only solution I could come up with was to use the scrollHeight property. But since it’s not W3C standard, I’d rather find some other solution).

    Other than that, great script!

  33. @Matan Nice edge case scenario. I’m not sure about the solution for that one, but if anyone has one please post a comment with the solution.

  34. @ Matan Arie & @William A quick solution to the scrollingDiv moving below the bottom of the page is to absolute position the scrollingDiv rather than using float. I’ve created a duplicate example using absolute positioning here: http://camwebdesign.com/demos/jquery-scrolling-element.html.

    Great example William, cheers!

  35. This is really useful! I have extended it so that it works for elements that start lower down the page and only need to stay near the top of the screen after you have scrolled past them:

    $().ready(function() {
    var $scrollingDiv = $(“#elementToScroll”);
    $(window).scroll(function(){

    if($(window).scrollTop() > 320 ){ // Start scrolling after this distance from the top – adjust it for what you need (trial and error or a ruler on the screen graduated in pixels ;) )
    $scrollingDiv
    .stop()
    .animate({“marginTop”: ($(window).scrollTop() – 300 ) + “px”}, “slow” ); // How many pixels to add to the distance
    }

    if($(window).scrollTop() <= 320 ){ // Less than this distance = RESET to original margin – set to 0 here but you can reset to your own original margin – this stops the element raising up too high up the page
    $scrollingDiv
    .stop()
    .animate({“marginTop”: “0px”}, “slow” );
    }
    });
    });

    Try this out – you may need to adjust the numbers a little bit to get it to work properly for you depending on what margins you already have associated with the DIV.

    Hope someone else finds this useful!

  36. @William, thanks for the useful code, it saved me considerable time researching this.

    @Peter: if you use scrollDiv.offset().top you can prevent a div scrolling from view to the top without having to hard code numbers. I was forced to use padding rather than margin as margin didn’t display properly.

    var scrollingDiv;
    $(document).ready(function() {
    scrollingDiv = $(“#scrollingDiv”);

    $(window).scroll(function() {
    var padding
    if ($(window).scrollTop() > scrollingDiv.offset().top) padding = $(window).scrollTop() – scrollingDiv.offset().top;
    else padding = 0;
    scrollingDiv
    .stop()
    .animate({“paddingTop”: padding + “px”}, “fast” );
    });
    });

    A working example can be seen at http://www.vanvanvans.com/designer The example includes a padding for when scrolled down and a check for smaller window size to prevent the always visible scrollable div pushing content down the page making it unaccessible.

  37. Thanks for the useful code and great explanation.

    An easier way to code an offset is by using the ternary operator instead of an ‘if’ statement:

    ” cond ? true : false ”

    The following code will only add a margin to the div if the window is scrolled beyond 400px

    var $scrollingDiv = $(‘#divName’);
    var $scrollingDivTop = 400;
    $(window).scroll(function(){
    $scrollingDiv
    .stop()
    .animate({“marginTop”: ($(window).scrollTop() < $scrollingDivTop ? 0 : $(window).scrollTop() – $scrollingDivTop) + “px”}, “slow” );
    });

  38. I wanted mine to have an undetermined position yet stop and stay at the top of the window when scrolling.

    $().ready(function() {
    var $scrollingDiv = $(“#headerScrollStop”);
    var position = $scrollingDiv.offset();

    $(window).scroll(function(){

    var view = $(window);
    var viewTop = view.scrollTop();

    if ($(window).scrollTop() > position.top) {
    $scrollingDiv
    .stop()
    .animate({“marginTop”: ($(window).scrollTop() – position.top – 40) + “px”}, “slow” );
    }
    else {
    $scrollingDiv
    .stop()
    .animate({“marginTop”: 0 + “px”}, “slow” );
    }
    });
    });

  39. Thank you so much for this awesome code! I implemented A.Land’s onto the site I’m working on. =]

  40. Anyway thanks, i got it working.. Very helpful guide..
    Thanks a lot…

  41. Hello,

    This was incredibly effective and useful – and plug-in-play! :D However, I noticed one bug – if one uses AJAX to dynamically change middle content of pages, and there is no noticeable scrolling that can be done on the pages, then the scrollingDiv will stay in the middle of the screen.

    For example, Page 1 allows you to scroll, and the Div moves accordingly. However, AJAX switches the page to Page 2, the div will stay in it’s same position, but won’t move back to the top when scrolling is taken away.

    Just a note, and wondering how to fix this. Thanks!

    - Caution

  42. Great Job.

    I used the example at http://www.vanvanvans.com/designer and works fine.

    Many thanks!

  43. It might be worth mentioning that this can sometimes get a little tricky when scrolling left and right – your div will try and wrap once it is out past the original right hand side of the screen. Setting white-space: nowrap seems to fix it.

  44. Great tutorial, thank you very much, jQuery was always powerful, but yet a bit tricky stuff :)

  45. I modiefied code so if you want to this scrolling div stop before some element in dynamic height page.

    $().ready(function() {
    var $scrollingDiv = $(“#nav”); //scrolling div
    var position = $(“#foot”).position(); // div before you want to stop
    var height = $(“#nav”).height(); //scrolling div can have dynamic height
    var pos = position.top – (height + 5); //adding some value so it wont stop very closely

    $(window).scroll(function(){
    if($(window).scrollTop() > 100 && $(window).scrollTop() < pos){ //100 is value after it start moving when scrooling
    $scrollingDiv
    .stop()
    .animate({“paddingTop”: ($(window).scrollTop() – 150) + “px”}, “slow” ); //150 is value that div appear at the top of the window
    }
    });
    });

    100 and 150 is values that you need to customize according to your website
    my foot and nav elements have position: absolute but ist not probably requiered
    if you have some questions feel free to ask me by mail

  46. Is there a way to remove the animation? I need the div to just stick to the top of the browser when a user scrolls down without any jquery animation.

    Thanks for this very useful tutorial! Cheers!

  47. Worked perfect, thank you!

  48. Great example… One problem i cannot figure out. My site has a HUGE FOOTER. Its about 1000px tall. I dont want the dive to scroll once it reaches the bottom of the page into the footer. I am not exactly sure how to accomplish this with the code.

    Any advice would be great.

  49. Thank you for this script, it works perfectly. Peter thank you for the adjustment, that was exactly what I needed.

  50. manuel benavides says:

    isn’t it easier just to user position:fixed; css property in combination with top and left to position the div, most cases not all it would be enough (like on a post that a need of the div not getting into the footer this won’t cut it).

  51. Thank you, it saved me lot of time! Very useful piece of jQuery.
    Claudio.

  52. Thanks william it is just perfect

  53. Florin Ivan:: use the below CSS class to position your div anywhere you want, certainly you have to play with the numbers (width, hieght, left….)

    .Floated { position: absolute; top: 95px; left: 30px; width: 220px; height: 40px; background-color: Olive; margin:auto; }

  54. Hello , half a problem I already fixed , but tell me how to make element stop scrolling after amount of pixels , because I have in the bottom pagination , and the pagination goes down with the scrolling div ?

    Any advice please !
    Thank you

  55. Nice work, really goes to show the power of JQuery with just a few lines of code.

    Keep it up!

  56. Hi, there – neat utility and just what I was looking for. However – didn’t you just KNOW that word was about to appear! – everything works fine on the page when the page is displayed normally. But, normally this page is displayed in a jQuery Overlay and the scroll seems not to work in such an instance.

    Any thoughts?

  57. Thanks for the plugin, I’m using it on my website to keep the navbar visible. I was inspired by recent changes to the Gmail interface that do the same thing. One Google search later I found you and viola!

  58. Brilliant. Thank you, i was just starting to get annoyed trying to work this out.

  59. Hi William,

    Thanks so much for the script. It was exactly what I needed :)

  60. worked perfectly thanks so much

  61. Excellent code!! Thanks a million!!!:))

  62. Thank you, I’ve been looking for something for days for something other than position:fixed!

  63. Hello,

    i have the same problem like Webdesign7. The scrolling element goes down to the footer, then the footer scolls, too. So i can never reach the end of the footer. Is there a code to tell the element some pixels where it hast to stop?

  64. Michelle Baxendale says:

    Just what I was looking for! Thanks William :)

  65. Hi William,

    Have you had issues using the jScroll plugin on Internet Explorer? The plugin works great on FF, Chrome and Safari but it doesn’t work at all with IE 7+

    Do you have any solutions? I’ll continue looking into a solution for this. I’m using jQuery 1.6.4.

    Thanks,
    Landman

  66. Thanks. This is great. Works like a charm. I was trying to do this with css, but the problem is if you used position:fixed, the div scrolls on browser window and not it’s containing div. Plus, the jquery gives it a much nice scroll effect.

  67. After much searching on Google with some very bloated results I was soooo happy to find this page! A great snippet!

    This worked like a charm in html5 responsive and looks awesome in the mobile version of the layout! Thanks so much!

    I only had 1 small issue but that was resolved in the comments by Peter McKane so thanks to all!!

  68. Works perfect and integrates very easily thank you.

  69. Thanks for this :)

  70. Also, to anyone else who may not be a CSS expert lol, I had a problem when I tried to alter the code out of my own ignorance that may save someone else some time. When I try to put a margin-bottom on the .scroll DIV, it made it so the container div kept expanding everytime I scrolled to the bottom. I took out the margin-bottom on the .scroll DIV and everything worked perfectly as it should.

    I also had a problem where I tried to add in some break tags to create some spacing after the .clear DIV and it had the same problem where the container div kept expanding everytime i scrolled to the bottom: (i substituted >’s and <'s for *'s just in case it messed up in this comment)

    *div class="clear"* */div*
    *br / *
    *br / *
    */div*

    Caused me some headache, but once I removed the break tags and had the code like it originally was:

    *div class="clear"* */div*

    */div*

    Everything worked great again! That's all for now, thanks again for a great plugin.

  71. Hi William,

    First of all thank you so much for this tutorial. I am using this solution and have found it to be very helpful. One question though. How do you prevent the scrolling element from scrolling too far up or too far down? I have a scrolling widget on a messaging page that I am working on. Basically it doesn’t have upper or lower limits. So if it scrolls down too far it begins expanding the content container downward. If it scrolls too far up it crashes into the page element that is located above. I’d be very grateful for any insights you may have. Once again many thanks for this great tutorial and plugin. I look forward to reading your future tutorials.

Trackbacks & Pingbacks

  1. links for 2010-11-30 « Caiwangqin’s delicious bog

    [...] Keep element in view while scrolling using jQuery | William Duffy (tags: jquery scrolling view) [...]

  2. Scrolling div using jQuery « ChocolateHedgehogBlog

    [...] [...]

  3. Siti ai Raggi X – Juventus + [Sondaggio] | Fedeweb

    [...] Per capire come รจ stato realizzato il menu che scrolla insieme alla pagina, puoi seguire questo tutorial. [...]

Leave a Reply