forked from caphun/jquery.stickysidebar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jquery.stickysidebar.js
131 lines (102 loc) · 3.53 KB
/
jquery.stickysidebar.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/**
* jQuery stickySidebar
*
* Copyright (c) 2011 Ca-Phun Ung <caphun at yelotofu dot com>
* Licensed under the MIT (MIT-LICENSE.txt) license.
*
* http://github.com/caphun/jquery.stickysidebar/
*
* Plugin to handle sticky sidebars.
*
*/
(function($){
// cached values
var namespace = '.stickySidebar',
stickyPrevScrollTop = 'prevScrollTop'+namespace,
stickyInitPosLeft = 'initPosLeft'+namespace,
stickyInitPosLeftGutter = 'initPosLeftGutter'+namespace;
// define stickySidebar method
$.fn.stickySidebar = function( options ) {
return this.each(function() {
new $.stickySidebar( this, options );
});
}
// plugin constructor
$.stickySidebar = function( elem, options ) {
// deep extend
this.options = $.extend(true, {}, $.stickySidebar.defaults, options );
// the original element | the parent element
this.element = $( elem );
this.parentElem = this.element.parent();
// run
this.init();
}
// plugin defaults
$.stickySidebar.defaults = {
gutter: 0 // defines the space to leave above the sidebar when it's sticky - default 0
}
// plugin prototypes
$.stickySidebar.prototype = {
init: function() {
// save initial values
this.initValues();
// define self
var self = this;
// here comes the magic!
$( window ).bind('scroll'+namespace, function() {
self.stickiness().data(stickyPrevScrollTop, $(this).scrollTop());
});
// when browser window is resized, start over with new position
$( window ).resize(function() {
self.initValues(true);
});
},
// actually, all the logic is here!!!
stickiness: function() {
var scrollTop = $( window ).scrollTop(),
elem = this.element, elemTop = elem.offset().top, elemHeight = elem.outerHeight(),
pTop = this.parentElem.offset().top, pHeight = this.parentElem.outerHeight(),
down = (scrollTop > elem.data(stickyPrevScrollTop));
return elem.css(
// if reached the element minus some gutter space we're entering sticky territory.
scrollTop > pTop - this.options.gutter
// if scrolling down check if reached the bottom of the parent container
&& ( (down && (pTop + pHeight > elemTop + elemHeight))
// if scrolling up check if scrollTop is less than the element top position
|| (!down && scrollTop <= elemTop) )
// sticky
? {
position: 'fixed',
top: 0,
left: elem.data(stickyInitPosLeft)
}
// not sticky
: {
position: 'absolute',
top: (pTop + pHeight <= elemTop + elemHeight ? pHeight - elemHeight : 0) - this.options.gutter,
marginTop: this.options.gutter,
left: elem.data(stickyInitPosLeft) - elem.data(stickyInitPosLeftGutter)
}
);
},
// save initial positions and values
initValues: function(resized) {
var elem = this.element;
if (resized) {
// save the current top offset
var top = elem.offset().top;
// reset to natural position in resized window (with new left offset)
elem.css({ position: 'static' })
// move to old top, with new left
elem.offset({ top: top, left: elem.offset().left });
} else {
// reset scrollTop value
elem.data(stickyPrevScrollTop, -1)
}
elem
.data(stickyInitPosLeft, elem.offset().left - parseInt(elem.css('marginLeft')))
.data(stickyInitPosLeftGutter, elem.offset().left - elem.position().left)
.css({ position: 'absolute', left: elem.position().left });
}
}
})(jQuery);