Skip to content

Instantly share code, notes, and snippets.

@sidonath
Created June 7, 2011 10:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sidonath/1011994 to your computer and use it in GitHub Desktop.
Save sidonath/1011994 to your computer and use it in GitHub Desktop.
A plugin for jQuery that makes element catch up with viewport
;(function ($) {
var $elementsToCatchUp = $(),
followBased = false,
bound = false;
function startCatchingUp($catchup) {
$catchup
.before($('<div>',
{ 'class': 'catching-up-placeholder', 'height': $catchup.outerHeight() }))
.addClass('catching-up')
.wrapInner($('<div>', { 'class': 'container' }));
if ($catchup.offset().top === 0) {
followBased = true;
}
}
function stopCatchingUp($catchup) {
$catchup.removeClass('catching-up').find('.container').children().unwrap();
// i am obviosuly forgetting here that there may be few catching up elements on one
// page and that this will remove all placeholders instead of only one
$('.catching-up-placeholder').remove();
}
function catchupHandlesWindowScroll() {
var scrollTop = $(window).scrollTop();
$elementsToCatchUp.each(function () {
var $catchup = $(this),
scrolledOutOfView = (scrollTop >= $catchup.data('top-offset'));
if (!$catchup.hasClass('catching-up') && scrolledOutOfView) {
startCatchingUp($catchup);
} else if ($catchup.hasClass('catching-up') && !scrolledOutOfView) {
stopCatchingUp($catchup);
}
// hardware-accelerated transition for iPhone
if (followBased) {
$catchup.css({
webkitTransitionProperty: '-webkit-transform',
webkitTransitionTimingFunction: 'cubic-bezier(0,0,0.25,1)',
webkitTransitionDuration: '0.2s',
webkitTransform: 'translate(0px, ' + scrollTop + 'px)'
});
}
});
}
$.fn.catchup = function (command, options) {
var $set = this,
opts = $.extend({}, $.fn.catchup.defaults, options);
if (command === 'stop') {
stopCatchingUp($set);
if (($elementsToCatchUp = $elementsToCatchUp.not($set)).length === 0) {
$(window).unbind('scroll', catchupHandlesWindowScroll);
bound = false;
}
return;
}
$set
.filter(opts.filter)
.each(function () {
var $this = $(this);
$this.data('top-offset', $this.offset().top);
});
$elementsToCatchUp = $elementsToCatchUp.add($set);
// bind scroll event only once and that only if collection is not empty
if (!bound && $elementsToCatchUp.length > 0) {
$(window).bind('scroll', catchupHandlesWindowScroll);
bound = true;
}
// if already scrolled
$(function () {
if ($(window).scrollTop() > 0) {
catchupHandlesWindowScroll();
}
});
return this;
};
$.fn.catchup.defaults = {
filter: function () { return true } // accept all incoming elements
};
}(jQuery));
// to start:
$('.some-element').catchup();
// to stop:
$('.some-element').catchup('stop');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment