-
-
Save ifthenelse/55f1e3226e263ca1c9bb to your computer and use it in GitHub Desktop.
Add an affix behavior to an element, by keeping it sticky between 2 elements.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;(function($) { | |
$.fn.extend({ | |
stickyWidget: function(options) { | |
// Exit if there are no elements to avoid errors: | |
if (this.length === 0) { | |
return this; | |
} | |
var settings = $.extend({ | |
header: '', // The page header or any element that the sticky module should be affixed | |
footer: '', // The page footer or any element that the sticky module should stop when it hits | |
minWidth: 980, // The minimum width to enable sticky - usually the width of the content area | |
threshold: 60, // An extra buffer added to the height when determining whether or not to enable | |
bufferTop: 0, // Distance from top of page element should stick (added to element bottom margin) | |
bufferBottom: 0 // Distance from footer to stop (added to element bottom margin) | |
}, options); | |
var sticky = { | |
el: $(this), | |
stickyLeft: 0, | |
stickyTop: 0, | |
stickyHeight: 0, | |
win: $(window), | |
header: false, | |
footer: false, | |
headerHasChanged: null, | |
threshold: settings.bufferTop + settings.threshold + settings.bufferBottom | |
}; | |
// Orginal positioning | |
var orig = { | |
mar: $(this).css('margin-left'), | |
left: $(this).css('left'), | |
top: $(this).css('top'), | |
pos: $(this).css('position') | |
} | |
var timer; | |
var stickyEnabled = true; | |
cacheElements(); | |
return this.each(function() { | |
buildSticky(); | |
}); | |
function buildSticky() { | |
sticky.win.bind({ | |
load: setupSticky, | |
sticky: setupSticky, | |
scroll: function () { | |
if (sticky.header.length) { | |
if (sticky.header.height() <= 158) { // yeah, magic static value | |
if (sticky.headerHasChanged == null || sticky.headerHasChanged == 0) { | |
setupSticky(); | |
calculateLimits(); | |
sticky.headerHasChanged = 1; | |
} | |
stick(); | |
} else { | |
if (sticky.headerHasChanged == null || sticky.headerHasChanged == 1) { | |
setupSticky(); | |
calculateLimits(); | |
sticky.headerHasChanged = 0; | |
} | |
} | |
} else { | |
stick(); | |
} | |
}, | |
resize: function() { | |
clearTimeout(timer); | |
timer = window.setTimeout(enableSticky, 200); | |
} | |
}); | |
} | |
function setupSticky() { | |
console.log("setupsticky!"); | |
var mid = sticky.win.width() / 2; | |
var widgetLeft = sticky.el.offset().left; | |
sticky.stickyWidth = sticky.el.width(); | |
sticky.stickyLeft = widgetLeft - parseInt(mid, 10); | |
sticky.stickyTop = sticky.el.offset().top; | |
sticky.stickyHeight = sticky.el.outerHeight(true); | |
enableSticky(); | |
} | |
// Caches elements into jquery objects | |
function cacheElements() { | |
if (settings.header !== '' && $(settings.header).length !== 0) { | |
sticky.header = $(settings.header); | |
} | |
if(settings.footer !== '' && $(settings.footer).length !== 0) { | |
sticky.footer = $(settings.footer); | |
} | |
} | |
// Only enable the sticky module if it's not going to break anything | |
function enableSticky() { | |
var ft = sticky.footer ? sticky.footer.offset().top : $(document).height(); | |
var track = (ft - sticky.threshold) >= (sticky.stickyHeight + sticky.stickyTop) && | |
// do not check whether sticky content is taller than window height | |
//sticky.stickyHeight < sticky.win.height() && | |
sticky.win.width() >= settings.minWidth && | |
'ontouchstart' in window === false; | |
if( track ) { | |
stickyEnabled = true; | |
} else { | |
stickyEnabled = false; | |
} | |
calculateLimits(); | |
stick(); | |
} | |
// Calcualtes the limits top and bottom limits for the sidebar | |
function calculateLimits() { | |
sticky.stickyStart = sticky.stickyTop - settings.bufferTop; | |
if(sticky.footer) { | |
sticky.stickyStop = sticky.footer.offset().top - sticky.stickyHeight - settings.bufferTop - settings.bufferBottom; | |
} | |
} | |
// Sets widget to fixed position | |
function setFixedWidget() { | |
sticky.el.css({ | |
position: 'fixed', | |
top: settings.bufferTop, | |
left: '50%', | |
marginLeft: sticky.stickyLeft, | |
width: sticky.stickyWidth + "px" | |
}); | |
} | |
// sets widget to a static positioned element | |
function setStaticWidget() { | |
sticky.el.removeAttr("style"); | |
} | |
// initiated to stop the widget from intersecting the footer | |
function setLockedWidget(diff) { | |
sticky.el.css({ | |
top: diff | |
}); | |
} | |
//determines whether sidebar should stick and applies appropriate settings to make it stick | |
function stick() { | |
var windowTop = sticky.win.scrollTop(); | |
var hitBreakPoint = stickyEnabled && sticky.stickyStart < windowTop; | |
if (hitBreakPoint) { | |
setFixedWidget(); | |
} else { | |
setStaticWidget(); | |
} | |
if (sticky.footer && sticky.stickyStop < windowTop) { | |
var diff = sticky.stickyStop - windowTop + settings.bufferTop; | |
setLockedWidget(diff); | |
} | |
} | |
} | |
}); | |
})(jQuery); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment