Skip to content
This repository has been archived by the owner on Mar 4, 2018. It is now read-only.

Commit

Permalink
Act on container height changes
Browse files Browse the repository at this point in the history
- Fixes #1
- Bump to 1.0.0
- Replace usage of jQuery functions to native functions
- Use single ticks instead of mixed double quotes and ticks
- Change the throw error to a console.error
- Add a setInterval check that checks each sticky instance's container height to see if it changed and needs to have it's boundaries updated
- Add CSS animation option
- Document methods and options better
- Add minified file
- Remove useFixed entirely, only relies on relative positioning now
  • Loading branch information
EnzoMartin committed Apr 14, 2016
1 parent 2d8972a commit d173a8f
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 72 deletions.
32 changes: 28 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,43 @@ Sticking an Element when Scrolling

This is a jQuery plugin to make an element scroll with the page inside the boundaries of a specified container.

There are many plugins like this, this one was built to be simple and lightweight.

###Usage:

```javascript
$('scrolling_item').sticky('scrolling_container');
$('scrolling_item_selector').sticky('scrolling_container_selector');
```

You can pass in a class or ID into either one. Note that the container will get set to position relative.

###Options:
| Name | Default | Description |
| ------------- | ------------- | ------------- |
| useTransition | true | Use native CSS3 `transition` property (recommended) |
| animate | false | Use jQuery animate function |
| animTime | 300 | Time it takes for animation to complete in `ms` |
| animDelay | 300 | Delay until the animation starts in `ms`, used only if `animate` is `true` |

**Note**: If you set `useTransition` to `true`, `animate` will always be treated as `false`

###Methods:

You can call various methods on a sticky element instance

* `useFixed`: Default: `true` - Setting this to `false` will instead always use relative positioning
* `animate`: Default: `false` - Setting this to `true` will animate the scrolling
* `animTime`: Default: `300` - Animation duration time
| Name | Description |
| ------------- | ------------- |
| `update` | Updates the position and boundaries of the element |
| `toggleFreeze` | Locks the element where it is until unfrozen |
| `setBoundaries` | Updates the top and bottom boundaries of the element |
| `moveIt` | Manually move the element to the scroll position within its parent boundaries |

####Example usage:

```javascript
// This will freeze/unfreeze the sticky element
$('#sticky').sticky('toggleFreeze');
```

## License

Expand Down
3 changes: 3 additions & 0 deletions demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,8 @@
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis libero lectus, rutrum sagittis egestas et, ultricies eu tellus.</p>
</div>
</div>
<div>END</div>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis libero lectus, rutrum sagittis egestas et, ultricies eu tellus. Nam eleifend, ligula vel dignissim adipiscing, quam elit tincidunt felis, ac venenatis tortor massa vel enim. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla condimentum augue sed nulla semper nec luctus enim vestibulum. Proin nec imperdiet nunc. Curabitur condimentum, nibh vel aliquet congue, augue felis sollicitudin arcu, in rhoncus nisi ipsum sed turpis. Morbi semper euismod sagittis. Vivamus vitae libero lorem, at imperdiet nisl. Quisque varius turpis eget nulla consectetur placerat. Vestibulum tortor nulla, luctus molestie consequat et, hendrerit a lorem. Ut ac nunc purus, vitae sodales neque.</p>
<p>Nunc id mauris in lacus pellentesque convallis sit amet in enim. Phasellus aliquam, mi in congue volutpat, nulla mi rutrum nisl, ut gravida risus mauris ac purus. Vivamus malesuada vestibulum augue et dapibus. Donec commodo orci eget dolor lobortis cursus. Maecenas sit amet malesuada odio. Sed posuere nisl pretium justo porttitor sed rutrum dui eleifend. Suspendisse a lacus ac massa fermentum mattis. Aenean ut mollis felis. Ut elementum ornare tincidunt. Fusce elementum mi in justo viverra quis elementum sem aliquam. Curabitur sit amet sem id lacus auctor semper. Nam in nibh eget odio mattis vestibulum vel ac libero. Maecenas at condimentum nisi. Aliquam elementum felis id libero porta non consectetur massa iaculis. Pellentesque consequat mollis porttitor. Etiam tempus arcu tellus.</p>
</body>
</html>
182 changes: 121 additions & 61 deletions jquery.stickyelement.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,73 @@
;(function($, window, undefined) {

"use strict";
;(function($, win) {
'use strict';

var requestFrame = (function(){
var raf = win.requestAnimationFrame ||
win.mozRequestAnimationFrame ||
win.webkitRequestAnimationFrame ||
function(fn){ return win.setTimeout(fn, 20); };
return function(fn){ return raf(fn); };
})();

/**
* Sticky Element constructor
* @param elm
* @param par
* @param options
* @param elm {String}
* @param par {String}
* @param [options] {Object}
* @constructor
*/
var Sticky = function(elm, par, options) {
this.element = elm;
this.parent = par;
this._frozen = false;
this.options = $.extend({
animate: false,
useFixed: true,
animTime: 300
useTransition: false,
animate: true,
animTime: 200,
animDelay: 300
}, options);

this.init();
};

Sticky.prototype.init = function() {
this.element.addClass("sticky-scroll");
var transition = '';
if(this.options.useTransition){
transition = 'top ' + this.options.animTime + 'ms ease-in-out';
this.options.animate = false;
}

this.parent.css({'position':'relative'});
this.element
.addClass('sticky-scroll')
.css({
'transition': transition,
'position':'relative'
});

this.update();
};

/**
* This will handle any resizing of the container the sticky scroll is in and update the boundaries if necessary
*/
Sticky.prototype.update = function() {
//This will handle any resizing of the container the sticky scroll is in and update the boundaries if necessary
this.setBoundaries();
this.setBoundaries(0);
this.moveIt();
};

/**
* This will decide whether to move the stickied item
*/
Sticky.prototype.moveIt = function() {
// This will decide whether to move the stickied item
var scrollTop = $(window).scrollTop();
var scrollTop = win.document.body.scrollTop;
var height = this.element.outerHeight(true);
var realStop = this._stop - height;

if (this._parentHeight - this._offset > height && !this._frozen) {
if (scrollTop >= this._start && scrollTop <= realStop) {
if(this.options.useFixed){
this.element.css({'position':'fixed','top':0,'left':this.element.offset().left});
} else {
this.updateOffset(scrollTop - this._start);
}
this.updateOffset(scrollTop - this._start);
} else {
this.element.css({'position':'relative','left':0});
if (scrollTop < this._start) {
this.updateOffset(0);
} else if (scrollTop > realStop) {
Expand All @@ -56,90 +77,129 @@
}
};

Sticky.prototype.setBoundaries = function() {
// This will set the boundaries the stickied item can move between and it's left position
this._offset = this.element.position().top;
/**
* This will set the boundaries the stickied item can move between and it's left position
* @param [offset] {Number} Manually set the element offset
*/
Sticky.prototype.setBoundaries = function(offset) {
this._offset = typeof offset === 'undefined' ? this.element.position().top : offset;
this._start = this.parent.offset().top + this._offset;
this._parentHeight = this.parent.outerHeight();
this._parentHeight = this.parent[0].offsetHeight;
this._stop = this._start + this._parentHeight - this._offset;
};

/**
* Update Stickied Element's offset
* @param yOffset
* Update Stickied Element's offset thereby moving it up/down the page
* @param yOffset {Number}
*/
Sticky.prototype.updateOffset = function(yOffset) {
if (!this._lastPosition !== yOffset) {
// This moves the item
if (this.animate) {
this.element.stop().animate({
if (this._lastPosition !== yOffset) {
if (this.options.animate) {
this.element.stop(true, false).delay(this.options.animDelay).animate({
'top': yOffset
}, this.animTime);
} else {
this.element.css('top', yOffset);
}

this._lastPosition = yOffset;
}
};

/**
* This will freeze/unfreeze the stickied item
*/
Sticky.prototype.toggleFreeze = function() {
// This will freeze the stickied item in place wherever it is
this._frozen = !this._frozen;
this.element.stop(true, false);
if(!this._frozen){
this.moveIt();
}
};

$.fn.sticky = function(par, options) {
var method, args, ret = false;
if (typeof options === "string") {
$.fn.sticky = function(parentName, options) {
var method = parentName;
var ret = false;
var args = [];

if (typeof options === 'string') {
args = [].slice.call(arguments, 0);
}

this.each(function() {
var self = $(this);
var parent = par;
if (parent) {
parent = self.parent().closest(parent);
} else {
parent = self.parent();
}
parent.css({'position':'relative'}); // Set parent position to relative
self.css({'position':'relative'}); // Set item position to relative
var instance = self.data("stickyInstance");
var instance = self.data('stickyInstance');

if (instance && options) {
if (typeof options === "object") {
if (instance && (options || method)) {
if (typeof options === 'object') {
ret = $.extend(instance.options, options);
} else if (options === "options") {
} else if (options === 'options') {
ret = instance.options;
} else if (typeof instance[options] === "function") {
ret = instance[options].apply(instance, args.slice(1));
} else if (typeof instance[method] === 'function') {
ret = instance[method].apply(instance, args.slice(1));
} else {
throw new Error("Sticky Element has no option/method named " + method);
console.error('Sticky Element has no option/method named ' + method);
}
} else {
var parent = null;
if (parent) {
parent = self.parent().closest(parent);
} else {
parent = self.parent();
}

instance = new Sticky(self, parent, options || {});
self.data("stickyInstance", instance);
self.data('stickyInstance', instance);
$.fn.sticky._instances.push(instance);
}
});
return ret || this;
};

/**
* Update the position/offset changed on resize and move, applies to all instances
*/
var updateAll = function(){
var len = $.fn.sticky._instances.length;
for(var i = 0; i < len; i++){
$.fn.sticky._instances[i].update();
}
};

$.fn.sticky._instances = [];
$.fn.sticky.updateAll = updateAll;

$(window).on({
'resize': function(e) {
// Update the position/offset changed on resize and move
$.each($.fn.sticky._instances, function() {
this.update();
});
$(win).on({
'resize': function() {
// Update the boundaries is the browser window is resized
updateAll();
},
'scroll': function() {
// Move all those suckers on scroll
$.each($.fn.sticky._instances, function() {
if (!this._frozen) {
this.moveIt();
// Move each unfrozen instance on scroll
var len = $.fn.sticky._instances.length;
for(var i = 0; i < len; i++){
var element = $.fn.sticky._instances[i];
if (!element._frozen) {
element.moveIt();
}
});
}
}
});

$(win.document).on({
'ready': function(){
// Start an interval to check the heights of sticky elements and update boundaries if necessary
win.setInterval(function(){
requestFrame(function(){
var len = $.fn.sticky._instances.length;
for(var i = 0; i < len; i++){
var element = $.fn.sticky._instances[i];
if(element._parentHeight !== element.parent[0].offsetHeight){
element.update();
}
}
});
},1000);
}
})
}(jQuery, window));
1 change: 1 addition & 0 deletions jquery.stickyelement.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions stickyelement.jquery.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,28 @@
"element",
"scroll"
],
"version": "0.0.2",
"version": "1.0.0",
"author": {
"name": "Enzo Martin",
"email": "enzo.r.martin@gmail.com",
"url": "https://github.com/EnzoMartin78"
"url": "https://github.com/EnzoMartin"
},
"maintainers": [
{
"name": "Enzo Martin",
"email": "enzo.r.martin@gmail.com",
"url": "https://github.com/EnzoMartin78"
"url": "https://github.com/EnzoMartin"
}
],
"licenses": [
{
"type": "MIT",
"url": "https://github.com/EnzoMartin78/Sticky-Element/blob/master/README.md"
"url": "https://github.com/EnzoMartin/Sticky-Element/blob/master/README.md"
}
],
"bugs": "https://github.com/EnzoMartin78/Sticky-Element/issues",
"homepage": "https://github.com/EnzoMartin78/Sticky-Element",
"docs": "https://github.com/EnzoMartin78/Sticky-Element/blob/master/README.md",
"bugs": "https://github.com/EnzoMartin/Sticky-Element/issues",
"homepage": "https://github.com/EnzoMartin/Sticky-Element",
"docs": "https://github.com/EnzoMartin/Sticky-Element/blob/master/README.md",
"dependencies": {
"jquery": ">=1.7"
}
Expand Down

0 comments on commit d173a8f

Please sign in to comment.