Skip to content

Instantly share code, notes, and snippets.

@p-m-p
Created May 7, 2011 21:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save p-m-p/960842 to your computer and use it in GitHub Desktop.
Save p-m-p/960842 to your computer and use it in GitHub Desktop.
StickySidebar jQuery plugin
(function($){
var settings = {
speed: 350 //animation duration
, easing: "linear" //use easing plugin for more options
, padding: 10
, constrain: false
}
, $window = $(window)
, stickyboxes = []
, methods = {
init:function(opts){
settings = $.extend(settings,opts);
return this.each(function () {
var $this = $(this);
setPosition($this);
stickyboxes[stickyboxes.length] = $this;
moveIntoView();
});
}
, remove:function(){
return this.each(function () {
var sticky = this;
$.each(stickyboxes, function (i, $sb) {
if($sb.get(0) === sticky){
reset(null, $sb);
stickyboxes.splice(i, 1);
return false;
}
});
});
}
, destroy: function () {
$.each(stickyboxes, function (i, $sb) {
reset(null, $sb);
});
stickyboxes=[];
$window.unbind("scroll", moveIntoView);
$window.unbind("resize", reset);
return this;
}
};
var moveIntoView = function () {
$.each(stickyboxes, function (i, $sb) {
var $this = $sb
, data = $this.data("stickySB");
if (data) {
var sTop = $window.scrollTop() - data.offs.top
, currOffs = $this.offset()
, origTop = data.orig.offset.top - data.offs.top
, animTo = origTop;
//scrolled down out of view
if (origTop < sTop) {
//make sure to stop inside parent
if ((sTop + settings.padding) > data.offs.bottom)
animTo = data.offs.bottom;
else animTo = sTop + settings.padding;
}
$this
.stop()
.animate(
{top: animTo}
, settings.speed
, settings.easing
);
}
});
}
var setPosition = function ($sb) {
if ($sb) {
var $this = $sb
, $parent = $this.parent()
, parentOffs = $parent.offset()
, currOff = $this.offset()
, data = $this.data("stickySB");
if (!data) {
data = {
offs: {} // our parents offset
, orig: { // cache for original css
top: $this.css("top")
, left: $this.css("left")
, position: $this.css("position")
, marginTop: $this.css("marginTop")
, marginLeft: $this.css("marginLeft")
, offset: $this.offset()
}
}
}
//go up the tree until we find an elem to position from
while (parentOffs && "top" in parentOffs
&& $parent.css("position") == "static") {
$parent = $parent.parent();
parentOffs = $parent.offset();
}
if (parentOffs) { // found a postioned ancestor
var padBtm = parseInt($parent.css("paddingBottom"));
padBtm = isNaN(padBtm) ? 0 : padBtm;
data.offs = parentOffs;
data.offs.bottom = settings.constrain ?
Math.abs(($parent.innerHeight() - padBtm) - $this.outerHeight()) :
$(document).height();
}
else data.offs = { // went to far set to doc
top: 0
, left: 0
, bottom: $(document).height()
};
$this.css({
position: "absolute"
, top: Math.floor(currOff.top - data.offs.top) + "px"
, left: Math.floor(currOff.left - data.offs.left) + "px"
, margin: 0
, width: $this.width()
}).data("stickySB", data);
}
}
var reset = function (ev, $toReset) {
var stickies = stickyboxes;
if ($toReset) { // just resetting selected items
stickies = [$toReset];
}
$.each(stickies, function(i, $sb) {
var data = $sb.data("stickySB");
if (data) {
$sb.css({
position: data.orig.position
, marginTop: data.orig.marginTop
, marginLeft: data.orig.marginLeft
, left: data.orig.left
, top: data.orig.top
});
if (!$toReset) { // just resetting
setPosition($sb);
moveIntoView();
}
}
});
}
$window.bind("scroll", moveIntoView);
$window.bind("resize", reset);
$.fn.stickySidebar = function (method) {
if (methods[method]) {
return methods[method].apply(
this
, Array.prototype.slice.call(arguments, 1)
);
} else if (!method || typeof method == "object") {
return methods.init.apply(this, arguments);
}
}
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment