StickyScroll - A stupidly simple jQuery plugin for fixed position elements

Posted 4 years ago by Rick Harris

We've been working on a couple of projects lately in which we wanted their statically positioned sidebars to stick to the top of the page when you scroll down. When the first project came along, I said "... I can do this" right before writing some custom javascript with hard-coded values. When the second project came along, my instinctual hatred for writing the same code over and over again kicked in and I wrote StickyScroll—a surprisingly (to me at least) flexible and compact jQuery plugin to take care of the heavy lifting.

Update: This post was written some time ago, and not all of its information is up-to-date. Please go to StickyScroll's GitHub page for the latest instructions or to report bugs

The main idea here is that these sticky elements need to be contained in some way. Obviously, when scrolling up a page, the sticky element needs to stop sticking when it returns to its original position. But I would argue that almost equally important is having a bottom boundary on the page where the sticky element will stop sticking so that it doesn't spill into the footer or even outside of the page itself. With no options provided, the plugin will use the <body> element as the bottom boundary. If you want to customize the bottom boundary, there's two approaches you can take:

1. Specify the containing parent

Say you have the following page structure:


<div id="header">
	...
</div>
<div id="container">
	<div id="content">
		...
	</div>
	<div class="sticky">
		...
	</div>
</div>
<div id="footer">
	...
</div>

You probably want the div.sticky element to be contained within the div#container.

How to make it so:


$('.sticky').stickyScroll({ container: '#container' });

2. Specifying a bottom boundary

One of the snags I came across was having an element that I wanted to be sticky, but it didn't have any special parent element to be contained within. In this case, there is a "manual" mode where you can specify a pixel offset, relative to the bottom of the document, as the bottom boundary for your sticky elements.

Example:


$('.sticky').stickyScroll({ mode: "manual", bottomBoundary: 150 });

In this example, the bottom of the sticky element will never be closer than 150 pixels away from the bottom of the document.

Use it

If you have use for it, try it out and let me know what you think.

A few notes:

  • Requires jQuery 1.4+
    Though, if you're like us, and you have constraints that don't let you upgrade to 1.4 quite yet, you can rip some code out from the jQuery source and make it work. Everything you need is here.
  • Using the container method does not mean that position: relative will be set on the container. StickyScroll does not alter the styling of anything other than the element it is called on.
  • We employ position: fixed styling on the sticky element, so IE6 is not supported

If you missed it before, here's the Github page.

49 Comments

KB ~ 4 years ago

I would love to see a working demo of this. I'm so far unable to get the script to work within an existing page, so I'm not sure if I'm not declaring the element that should be stuck correctly or am missing CSS (there's no info on the "sticky-process" selector called in the script?). I've been trying to modify existing scripts to do just what this one does, so I would be thrilled to get this working.

Wesley ~ 4 years ago

Nice plugin, KB, the reason it's not working is because there is a syntax error in the script. Line 82 should be changed to simply "};" without ().

A few kinks for me though:

My div is 1 of 2 columns (each 49.1% wide). Due to the plugin the div's width increases on first scroll.

Secondly, when I scroll back up it goes beyond it's original position. I would want it contained to where it was if possible.

And thirdly, an "easing" animation option instead of this fixed design would be great.

I'm currently using http://www.wduffy.co.uk/blog/keep-element-in-view-while-scrolling-using-... until the kinks are worked out here. That one works well but it's not at the top of the body boundary unlike yours. There seems to be a big margin-top there.

Wesley ~ 4 years ago

Well, I was able to customize the snippet from the site I linked to do what I wanted, it may interest you:

var $scrollingDiv = $("#preview-div");
var elemTop = $scrollingDiv.offset().top;

$(window).scroll(function(){
$scrollingDiv.stop();

if ($(window).scrollTop()>elemTop) {
$scrollingDiv.animate({"marginTop": ($(window).scrollTop()-elemTop) + "px"}, "slow" );
} else {
$scrollingDiv.animate({"marginTop": "0px"}, "slow");
}
});

Rick Harris ~ 4 years ago

@Wesley and @KB, looks like my most recent commit of stickyscroll really messed some things up. I'm working on a fix, and I'll let you know when it's up.

Rick Harris ~ 4 years ago

The updated version with demo pages is up at http://github.com/rickharris/stickyscroll.

@Wesley - I like that the solution you found doesn't require fixed positioning, especially since fixed positioning doesn't quite work how you would expect on the iPhone/iPad. I'm not sold on animations, as I imagine there would be a delay between scrolling and the sticky element moving to the position you just scrolled.

KB ~ 4 years ago

Thanks, Rick! Works like a charm.

I was trying to modify another script that used the animation approach for the reason you stated: there had to be a delay between the scrolling and animating as otherwise the div would jerk up and down while scrolling. I'll most likely build a separate mobile/iPhone/iPad version for this project, but the issue with fixed positioning is good to know.

Nintensity ~ 4 years ago

Hey! Thanks for the plugin. But unfortunately, I have uncovered a bug!

It works when the web layout is designed with a fixed grid. On a fluid grid layout, it would work, however, the location where the fixed container will stop upon scrolldown will vary because the content's height will expand/contract depending on the user's window size.

My webdesign is using a fluid grid, if any ideas, please help me!

Rick Harris ~ 4 years ago

You're right -- I didn't consider fluid layouts. I'll try to add support for them.

Nintensity ~ 4 years ago

Thanks Rick!!! I really appreciate your work in helping me and for others. Once you get it going on a fluid grid... This plugin is gonna be the bomb!

Mark ~ 4 years ago

Rick...
First off, thanks for the code!! I was incorporating it today and noticed this. Hopefully you can follow me around this explanation. I have a page that starts short with no scroll bars and then grows longer if a user selects a checkbox that grows the page to a length with scroll bars. Browser is Safari so the scroll bars are hidden until the page needs them. Before the page grows the sticky div works as expected. After the page grows and the scroll bars are added and you scroll down the div does move with the top of the browser but it also jumps to the right approximately the distance of the added scroll bars. I assumed this had to do with the leftOffset. I've moved the leftOffset to inside the onScroll() function so that it is constantly getting calculated. I did this with no knowledge of the consequences but now it works like it should. Here is the code. It'd be great to know if this is a bad thing or a good thing. http://pastie.org/1158890

Rick Harris ~ 4 years ago

Thanks Mark!

I can see where the plugin, as it is now, wouldn't react well to dynamically changing layouts, especially horizontal ones. Your code looks logical, I'll test it out and if it still looks good I'll add it in.

In the meantime, if you don't like having that extra calculation every time the scroll event gets called, you can add html { overflow-y: scroll; } to your global CSS file to force a scrollbar, even when you don't need it. IE7 does this by default, and believe it or not, I've come to prefer it. It makes going through pages that may or may not require scrolling more consistent.

Mark ~ 4 years ago

How in the world have I never thought of that to force the scroll bar. It is basically my only gripe when developing sites and viewing them in Safari, my default browser. Thanks again!!

Nintensity ~ 4 years ago

Hey Rick, I definitely appreciate the effort help to make this plugin.. but I assure you, once you get it working, it's gonna be the bomb!

Any news on the Fluid layout workaround?

Rick Harris ~ 4 years ago

No progress. I have looked at it and tested out some ideas, but I think support for fluid layouts is going to be left out for now.

I have two ideas for how I'm pretty sure I could make it work, but one requires extra markup and one would cause a momentary flash of style, potentially causing a flickering/disappearing sticky element whenever the window is resized, and I'm not satisfied enough with either of those compromises to add support in.

You are, though, more than welcome to fork it on Github and add what you need to it :)

Rick Harris ~ 3 years ago

Good news!

The most recent version of StickyScroll has support for fluid layouts! I just pushed it to Github. Let me know how it works out for you

StatVoid ~ 3 years ago

Is there a way to use this so, for example, a div is placed on the bottom-right of a screen and fixed, and when you reach the footer of the page, the div then scrolls up and stays atop the footer? Also, if the footer is high on the page (as if the content weren't enough to take up the full page and make it scrollable), could that div still sit atop of the footer?

I apologize, I'm a total newbie when it comes to java.

:-/

Rick Harris ~ 3 years ago

No need to apologize! We all were beginners at some point.

First things first: we're working with Javascript here, not Java. Similar names, but very different languages.

Secondly, no, StickyScroll doesn't do what you're describing. This plugin really only applies to elements that start out statically positioned on the page (that is to say, not fixed at all), and then become fixed (or "sticky") to the window as you scroll past them). The plugin doesn't really help if the element in question starts out fixed.

What you want to do and what StickyScroll does for you are pretty similar, though. It would be possible to adapt the plugin or extract some code to do what you need. Lines 69-120 in jquery.stickyscroll.js are the main chunk of it. It's pretty poorly commented, so I apologize in advance for that. I'll try to add some helpful comments soon.

StatVoid ~ 3 years ago

Hmmmm, maybe I didn't mean fixed, per se.

To give you a visual, it's kinda like a puzzle. This element (approx. 150px x 150px), when you load the page, looks fixed to the content wrapper, like 50px from the bottom and 50px from the left of the wrapper's border. As you scroll it stays put, until you reach the footer (approx. 300px). Once it hits the footer, it moves with the rest of the document to the bottom. When you scroll back up, it returns to it's set position on the screen.

I hope that gives you a better idea of what I am thinking.

I've been searching for upwards of 15 total hours and I can't find anything that's just right. All tutorials I've seen are basically written to keep things toward the top of a page, I just don't know how to convert them to work on the bottom.

Rick Harris ~ 3 years ago

Yeah, that's pretty much what I was imagining. The problem is that StickyScroll is meant to do a pretty specific thing well, and not try to solve every single problem. So, it's really good at making a specific kind of sticky sidebar, which doesn't include one that sticks to the bottom of the page, like what you're describing.

Like I said, the logic from StickyScroll could be extracted and edited to do what you need, but I can't promise that functionality will be incorporated into the plugin. Sorry to disappoint!

evan ~ 3 years ago

Its a great plugin to have however, there doesn't seem to be a way of positioning the element you want to be sticky. For example, i'm using this sticky plugin to allow the nav bar (that sits at the top of my page), to scroll with the user until a certain point on my page, which I have working fine. When the page is initially loaded the positioning of my nav is how I want it to look (40px from the top) but as soon as I start to scroll down the page it jumps to the very top of the browser window & remains there. How do I ensure my nav stays 40px from the top always? I can't seem to style this sticky element when it is active?

Any help appreciated!

Rick Harris ~ 3 years ago

How do you position the element initially? Since StickyScroll takes care of any relative/absolute/fixed positioning for you, be sure that your element starts out statically positioned and use margin or padding (margin is probably the more correct answer, but padding is probably safer with StickyScroll) to position it, and everything should be great.

Evan ~ 3 years ago

Still no luck i'm afraid. Its position is fixed but even after changing it to static, it still reproduces the same problem. It also then interferes with the rest of my style sheet & the way i've coded up the page as the nav then disappears behind other elements. Here is what I have for the nav element (i.e. the element I would like to be sticky):


/* primary */
nav { position: static;
background: url(../images/get-to-know-me.png) top left no-repeat,
url(../images/side-projects.png) top right no-repeat;
padding-top: 40px;
height: auto; }
span.nav-title { background:url(../images/side-projects.png) top center no-repeat; }
nav ul { width: 960px; margin-left:0; }
nav ul, nav li { display:inline; float:left; }
nav ul li { width:120px; }

nav ul li#right-inner,
nav ul li#right-outer { float:right; }

nav ul li a,
nav ul li a:visited,
nav ul li a:active {
padding: 1.2em 0 1.4em 0;
color: #464239;
letter-spacing: .17em;
font-size: 1em;
text-transform:uppercase;
text-decoration:none;
text-align:center;
display:block;
line-height: 1em;}

nav ul li a span,
h1 span.subtitle {
text-transform:none;
letter-spacing:normal;
color: #a23b12;
display:block;
font-style:italic;
font-size:72%; }

/* /primary */

Does anything seem out of place to you?

Rick Harris ~ 3 years ago

Hmm. A few things:

  1. Look at the README on the Github page for the latest usage instructions, as this page is kind of out of date. It sounds like you're using the "manual" mode, for which the usage is a little bit different now than what this page says. You can play around with your margins/padding and the topBoundary setting until you get it right.
  2. If your element is going behind your other page elements, use z-index. Even though the initial positioning is static, the z-index will take effect once StickyScroll has done its thing.

Hope this helps!

evan ~ 3 years ago

Thanks for your help on this, i'm not that great at scripting & this probably really basic but how do I implement the following code (taken from the usage instructions on GitHub):


jquery_collection.stickyScroll({ topBoundary: '100px', bottomBoundary: '200px' })

I used the above & added it to $('#prim') so it looked like:


$('#prim').jquery_collection.stickyScroll({ topBoundary: '100px', bottomBoundary: '200px' })

but it didn't work at all.

Rick Harris ~ 3 years ago

the jquery_collection just represents what is returned by $('#prim'), so you can drop it. I've updated the README on Github to be more clear.

jf ~ 3 years ago

Hola. Ive been using this for a few weeks now, but it seems the latest version of chrome has a problem with it now?

Rick Harris ~ 3 years ago

Yes, indeed. The issue is already on github. I'm looking into possible solutions.

jf ~ 3 years ago

Rick,

Hola. yeah I also posted the issue on github. I really like stickyscroll and if you need any help testing solutions let me know!

Raff ~ 3 years ago

Great script but it doesn't seem to be working in IE, maybe I missed it in the comments but is there a solution?

derby42 ~ 3 years ago

hi,
does stickyscroll support only top positioned divs or also a left navigation for example!?
does the script effects only when the user is on an ipad/iphone/ipod?
best
derby42

Asp .Net Web Development ~ 3 years ago

I tried this one but its not working properly with my Mozilla latest version as well.Suggest me the solution please.

Visitor ~ 3 years ago

I really need this to work with jquery 1.3.2 but cant get it done, isWindow is not a function jquery.contains has the same error...

guldam ~ 3 years ago

I'm getting the same error. $isWindow is not a function

Rick Harris ~ 3 years ago

Well, there's two problems here, really. The first is that it's not meant to be used with anything less than jQuery 1.4. The second being the StickyScroll isn't really meant for use anymore. It's broken in the latest versions of Safari, Chrome, and Firefox, and for now I'm taking it as a sign that man was not supposed to imitate fixed positioning with Javascript. Both of those warnings are up on the Github page. Sorry to disappoint!

Michal ~ 3 years ago

Im not behind my pc now. In the evening ill post what you need

Michal ~ 3 years ago

It all works you just need tobtweak everything ill send everything later.

Lotte Mygind ~ 2 years ago

Hello Rick,

I have just started to use StickyScroll (initially overlooking the warning on GitHub). Anyway, I had problems in Internet Explorer. After a bit of debugging, I realized that my problem was the call to Date.now, which is not supported by IE until version 9. I couldn't really figure out why the time was needed, so I just tried to remove the call to Date.now(). So I use:

id = index,

instead of

id = Date.now() + index,

According to my tests, this works fine in IE8, Firefox 8.01, Chrome 15.0.874.121 and Safari 5.1.2.

If you can give me a hint about why the date/time is necessary, it would be much appreciated :-)

Best regards,
Lotte Mygind

Chris ~ 2 years ago

I fixed this problem changing line 72 to the following:


dDate = new Date,
id = ((!Date.now) ? dDate.getTime():dDate.now()) + index,

Works fine in every browser for me.

DirkO ~ 2 years ago

Great script!
is there any chance to apply some easing, when the position changes?
As far I experienced it' quite jumpy / flickering while scrolling the page.

Rick Harris ~ 2 years ago

Sorry, this script is outdated and isn't seeing updates anymore. The flickering started happening some time ago and I never came up with a solution to fix it. There's more info on the github page about it.

Chris ~ 2 years ago

If Internet Explorer is not that important, you could just add to the element
transition: all 0.2s ease-in-out;

Then play around with .sticky-active and .sticky-inactive

Craig Moss ~ 2 years ago

Thanks for the great plugin Rick, worked with a bit of tom foolery, had to adjust the topBoundary so it would not do a funny bounce when scrolling back to top, this sorted out the problem even if it always sets the margin from the top...see my script code below for more information

$(function(){
var el = $('#container_right'),
top_offset = $('#container').offset().top;

$(window).scroll(function() {
var scroll_top = $(window).scrollTop();

if (scroll_top > top_offset) {
el.css('top', scroll_top - top_offset);
}
else {
el.css('top', '');
}
});

$('#container_right').stickyScroll({ container: '#container',topBoundary: '150px', bottomBoundary: 150})
});

Sumith ~ 2 years ago

Thanks.
This is another example with demo and source code.
http://faq.pctrickers.com/jquery-sticky-scroll-plugin-example/

Andre ~ 2 years ago

wow!
this plugin helped me
Thanks!

JamesMax62 ~ 1 year ago

Great plugin Rick. It works fine for me except the sidebar doesn't stop within the bottom of the container. I have no idea why. My sidebar is an Ad Banner Tower of 160x600 and it doesnt stop within the bottom of the container. I have the container set to overflow:hidden so it is actually getting cut off. If I dont have overflow:hidden then the sidebar overflows on to the footer. I am using the auto mode and cannot use the manual flow as the container size is dynamically determined. Please help!!!

Bennart ~ 1 year ago

nice plugin
but how i can animate the sticky div when scrolling?

Visitor ~ 1 year ago

Um in your demo the stickied element jumps up and down instead of staying fixed in place... like fidgeting or something...

Visitor ~ 1 year ago

How about a top boundary so it's always X pixels away from the top? Is there an option for that?

thủ thuật ~ 1 year ago

Great script!
is there any chance to apply some easing, when the position changes?
As far I experienced it' quite jumpy / flickering while scrolling the page.

For reservations, call office(800) 890-1702. Send fan mail to our work location at 2 North Main Street, Greenville, SC 29601-2719 USA 34.850823 -82.398746
Lovingly crafted by orangecoat with some rights reserved, and a promise not to spam you.

Back to top