I am available for freelance work - HIRE ME

Making of the Contained Sticky Scroll jQuery Plugin

posted by Matt Ward on Nov 27, 2010.

Last week I released a jQuery plugin that I called Contained Sticky Scroll, which you can see working on the sidebar of this blog. In this tutorial, I will be going through the code of that plugin and explaining how to write the plugin entirely from scratch!

Last week, I made a slight tweak to the blog’s functionality. You can see the effects of this change in the sidebar, which should stick to the top of the page as you scroll down, but which won’t actually scroll out of the main content area. This is achieved using a custom coded jQuery plugin that I created for this exact purpose. I’ve dubbed it the Contained Sticky Scroll plugin, and released it as a freebie. If you haven’t downloaded it yet, be sure to check it out.

Anyhow, I thought it might also be interesting to take a deeper look at the code and the process that I used to write the plugin, so that’s what this post will be about.

As with any coding project, the first step is to determine the basic objectives of what we’re looking to accomplish. In this case, my main objectives were:

  • To have a sidebar that would hug or “stick” to the top of the screen as a reader scrolls down the page, thus prolonging the visibility of the ads on the blog.
  • Scrolling shouldn’t start until the top of the sidebar drifts above the top of the window.
  • Scrolling should stop once the scrolling reaches the bottom the main content area, so that the sidebar does not hover down over the comment and footer areas, since this would look horrible in the context of the site’s overall design.
  • There needs to be a way to unstick the sidebar, for users who may not like the stickiness

From the outset, it was abundantly clear to me that jQuery was going to be the best solution. It’s the one JavaScript framework with which I am the most familiar, and I’ve been working with it extensively over the past several months in some unrelated development work. It also has a robust library of animation based functionality, and methods for retrieving positioning information that will be vital for what I was trying to accomplish.

As such, to start, we’ll want to basically define the basic structure for our plugin:

(function( $ ){

  $.fn.containedStickyScroll = function( options ) {

  /* Code will go here */

  };
})( jQuery );

This code basically initiates a new method and attaches it to the universal jQuery object. Now we can utilize this method, called containedStickyScroll by calling the basic jQuery object. The method will also accept a collection of options, which should be passed as a basic JSON object (just like any other jQuery plugin).

For any plugin that uses options, we also need to set default values to be used in the event that an option is not specified by the user. In practice, it is very common for plugin methods to be called with only a few of the available options. Often, no options are supplied at all! So, it’s very important to declare defaults for values that will be needed as the plugin executes.

To set our defaults, we just need to create a simple object like this:

var defaults = {
   unstick : true,
   easing: 'linear',
   duration: 500,
   queue: false,
   closeChar: '^',
   closeTop: 0,
   closeRight: 0
} 

Let’s walk through these options quickly. First the unstick option basically tells the plugin whether or not the unstick functionality should be activated. We have defaulted this option to true.

Next, we have easing, duration and queue, all of which are options that will be passed directly to the jQuery.animate() method that is used to actually move our sticky element across the screen. These default settings worked particularly well for me as I was developing the plugin, and are the values used for its implementation on this very blog.

Lastly, we have the closeChar, closeTop and closeRight options, which control the positioning of the trigger, which will unstick the scrolling element (setting it back to its static position) if the unstick option is set to true. closeChar simply allows the user to tell the plugin what character string to use as the trigger, while closeTop and closeRight offer a bit of precision control for tweaking the placement of the trigger in the top right corner of our scrolling element.

Now, if we felt so inclined, we could easily add further options that would also allow us to chose how we want to align the trigger vertically (top/bottom) and horizontally (left/right). This is something I may add into a future version.

Next, we want two lines of simple code to initialize options that can be retrieved later, by the rest of the plugin.

var options =  $.extend(defaults, options);
var $getObject = $(this).selector;

In the first line, we are basically merging the values of the defaults object that we created with the options passed to the plugin method. Any option that has been explicitly supplied will be retained, while any option that is not supplied will be set to its default value. By doing this, we will now have a single, unified options object that we can reference as required.

In the second line, we’re basically accessing the selector that we used to target the scrolling element and storing that value to a variable. We will be using this value in the actual animation, which is the next step in the process.

Now stick with me here! This block of code may seem complex at first glance, but the logic is really simple. Here is the code, which I have colour coded to help break it down:

jQuery(window).scroll(function() {
  if(jQuery(window).scrollTop() > (jQuery($getObject).parent().offset().top) &&
  (jQuery($getObject).parent().height() + jQuery($getObject).parent().position().top - 30) > (jQuery(window).scrollTop() + jQuery($getObject).height())){
    jQuery($getObject).animate({ top: (jQuery(window).scrollTop() - jQuery($getObject).parent().offset().top) + "px" },
    { queue: options.queue, easing: options.easing, duration: options.duration });
  }
  else if(jQuery(window).scrollTop() < (jQuery($getObject).parent().offset().top)){
    jQuery($getObject).animate({ top: "0px" },
    { queue: options.queue, easing: options.easing, duration: options.duration });
  }
});

If we use the colour coded areas as guideline, we can translate this into normal language to read:

[When jQuery sees the window scroll] {
  if(the top of the window is GREATER than the top of the element) AND
  (the bottom of the parent is GREATER than the bottom of the element){
    animate element to({ set top position to match the value top of the window },
    { setting queue, easing and duration });
  }
  else if(the top of the window is LESS than the top of the element){
    animate element to({ set top position to 0 },
    { setting queue, easing and duration });
  }
});

Hopefully that actually makes sense to you. It’s really pretty simple. Basically, whenever the window scrolls, jQuery will execute this function. It will check to see if the top of the window is greater in value (meaning the user has scrolled past) the top of the selected element. If it is, then one condition is met. However, the function also checks to make sure that the bottom of the element does not extend past the bottom of its parent. If both of these conditions return true, the function will then trigger an animation which will reposition the element to the top of window.

One thing that is probably worth noting is how we determine the bottom values. As far as I have been able to tell, jQuery does not have a native method to return the bottom of an element the way it returns the top. However, it is relatively easy to compute based on information that we can get. If we take the current top position of the element and add it to the full height of the element, that will actually give us the bottom position.

For example, if our element is sitting 130px from the top of the document and has a height of 445px, then the bottom position can be calculated as 130 + 445, which equals 575. Thus, the bottom of the element would be sitting at 575px from the top of the document, and we would not want the bottom of our scrolling element to move beyond that.

Alright, now we have most of our code written, and if you were to test out the plugin at this point, it should be able to display the sticky scroll behaviour that we are looking for. The only thing left to do is to include the necessary code to make the unstick trigger display. We will do this by adding an extra bit of HTML to the bottom of our scrolling element and then using some generated CSS to control the positioning. Additionally, we will wrap the entire procedure in a conditional statement, so that it will only trigger when the unstick option is set to true.

if(options.unstick == true){
  this.css('position','relative');
  this.append('' + options.closeChar + '');
  jQuery($getObject + ' .scrollFixIt').css('position','absolute');
  jQuery($getObject + ' .scrollFixIt').css('top',options.closeTop + 'px');
  jQuery($getObject + ' .scrollFixIt').css('right',options.closeTop + 'px');
  jQuery($getObject + ' .scrollFixIt').css('cursor','pointer');
  jQuery($getObject + ' .scrollFixIt').click(function() {
    jQuery($getObject).animate({ top: "0px" },
    { queue: options.queue, easing: options.easing, duration: options.duration });
    jQuery(window).unbind();
    jQuery('.scrollFixIt').remove();
  });
} 

The .append() and .css() methods are fairly self explanatory. The important one is the .click() method, which binds the included function to the trigger. This way, when someone clicks it, jQuery will immediately scroll the sticky element back up to its default position. It will then use .unbind() to deactivate the scroll listener from the window and the .remove() method to delete the generated trigger.

And that’s pretty much it! I will note that in the actual plugin, I placed the conditional unstick code before the scroll listener (though it could also go after it with no real effect). It was, however, the last bit of code that I wrote, so it made sense to save it to the end to talk about.

Regardless, if you want to see how it all together, why not download the plugin for yourself? Just click the image below!

Freebie: Contained Sticky Scroll jQuery Plugin (Downloaded 19168 times)

Freebie: Contained Sticky Scroll jQuery Plugin (Downloaded 19168 times)

The download package contains both full and minified versions of the .js file, along with a demo page which explains the various options that can be used to configure each initialization of the plugin’s functionality. If you want to check out the demo page without actually downloading the entire package, I’ve also uploaded it here.

View the demo

So there you have it! Now you can either download the plugin or write it yourself. Either way, I hope you found this tutorial interesting, and that it’s provided you with the basic building blocks for creating your own jQuery plugins!

Post A Comment

Also from Echo Enduring Media:

An Unfolding Tale

About the Author

Matt Ward is a digital artist who lances freely under the moniker of Echo Enduring Media, and specializes in graphics design, illustration and writing. He is also the Creative Director for Highland Marketing, a creative direct marketing company based out of Waterloo, Ontario. You can follow Matt on Twitter

Like this post? Help Promote it!

Comments

Nov 27, 2010

kashif says:

where is the demo man, its a dead link

Nov 28, 2010

Matt Ward says:

All fixed up

Nov 28, 2010

Mark says:

Nice. Thanks.

Is there a way to turn the easing off? In terms of UX I personally find the “bounce” a little annoying. The disappearing then coming back is distracting to the eye.

I do like the fact that come the bottom of the page it doesn’t display over the footer area. That’s a nice touch

Nov 28, 2010

Matt Ward says:

It might be possible to do something like that using fixed positioning instead of the .animate() method. I’d have to do some playing around though.

Nov 28, 2010

ChrisK says:

I did something similiar:

http://wi.uni-graz.at/drupal/

Look at the Facebook-Box

Nov 28, 2010

hutch says:

it’s really jittery and laggy. you should look at this and adapt it. http://jqueryfordesigners.com/fixed-floating-elements/

Jan 12, 2011

James says:

Thanks for this. I like it, it’s not at all laggy for me.

Mar 18, 2011

linaa says:

thank you but what sould I do to put the element to the bottom of the screen?

Apr 19, 2011

Jason Sebring says:

I make plugins and hadn’t made one for this instance and don’t plan to but I have made this behavior many times. I find your easing effect to be undesirable as it a bit distracting. I understand why you did it but I have a work around to avoid the “jerkyness” of doing absolute positioning without needing a setTimeout as you are probably doing then using some Robert Penner easing equation implementation that jQuery uses.

See my code here -> http://klim.jasonsebring.com/ there are icons on the left that stick to the top then unstick themselves. Apple and DELL to name a few use this behavior instead for their carts because its more desirable. The following widget then doesn’t seem to follow, rather just stays as part of the background fixed. The unique part of my solution is it using a “dynamic-fixed” approach by dynamically setting the top-left of a position:fixed element as you scroll. This icon on the right is sticking to the centered edge of the div’s right rather than being relative to the window edge as position fixed forces. You will comprehend this I’m sure and then adjust your code accordingly.

Jun 25, 2012

woodstudio says:

hello, nice plug-in !!!!!!!
can you explain the right way to make it work with wordpress sidebar please ?
thanks

Jun 25, 2012

woodstudio says:

forget it ,
i found how to do it :)

Leave a Comment

Copyright © Echo Enduring Media 2009-2014