-
Notifications
You must be signed in to change notification settings - Fork 40
/
jquery.stickystack.js
193 lines (147 loc) · 4.84 KB
/
jquery.stickystack.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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
/*!
**********************************************************
* StickyStack.js
*
* Version: v1.1.2
* Author: Mike Zarandona
* Release: June 24 2014
* Added a fix for sections that are taller than the screen
*
* Reqs: jQuery
*
* Usage: $('.main-content-wrapper').stickyStack({
* containerElement: '.main-content-wrapper',
* stackingElement: 'section',
* boxShadow: '0 -3px 20px rgba(0, 0, 0, 0.25)'
* });
**********************************************************
*/
(function ($, undefined) {
$.fn.stickyStack = function (options) {
/* Override defaults with specified options. */
options = $.extend({}, $.fn.stickyStack.options, options);
// Variables setup
var $sections = $(options.containerElement + ' > ' + options.stackingElement),
sectionsInfo = [],
// Build the styles
styles =
options.stackingElement + '{' +
'box-sizing: border-box;' +
'-moz-box-sizing: border-box;' +
'position: relative;' +
'z-index: 100;' +
'}' +
options.stackingElement + '.stuck {' +
'position: fixed;' +
'top: 0;' +
'z-index: 0;' +
'}' +
options.stackingElement + '.stuck + ' + options.stackingElement + ':not(.stuck) {' +
'box-shadow: ' + options.boxShadow + ';' +
'}' +
options.stackingElement + '.stuck.align-bottom {' +
'top: auto !important;' +
'bottom: 0 !important;' +
'}';
// Append the styles to the <head>
$('head').append('<style id="sticky-stack-styles" type="text/css">' + styles + '</style>');
// Document ready()
$(document).ready(function() {
buildSectionsInfo();
// Fix the section width
var origWidth = $sections.eq(0).outerWidth(true);
$sections.css('width', origWidth + 'px');
});
// Window scroll()
$(window).on('scroll', function() {
// Current scroll position
var windowScrollPos = $(window).scrollTop(),
// Counter variable
counter = 0;
// Count how many sections should be stuck
for (var t = 0; t < $sections.length; t++) {
// if this section has an offset, use that instead
if ( $sections.eq(t).attr('data-offset') != 0 ) {
if ( windowScrollPos >= sectionsInfo[t][2] + sectionsInfo[t][0] ) {
counter++;
}
}
else {
if ( windowScrollPos >= sectionsInfo[t][0] ) {
counter++;
}
}
}
setStickies(counter);
});
// Resize event to keep the site width fluid
$(window).on('resize', function() {
$sections.css('width', $(options.containerElement).width() + 'px');
buildSectionsInfo();
});
function setStickies(howMany) {
// Step 1: Calculate how much padding the parent container should get
var paddingTop = 0;
// Total the amount of padding of stuck sections
for (var p = 0; p < howMany; p++) {
paddingTop += $sections.eq(p).outerHeight(true);
}
// Append that height to the parent wrapper
$sections.eq(0).parent().css('padding-top', paddingTop);
// Step 2: Stick the sections to be stuck (heh)
for (var s = 0; s < $sections.length; s++) {
if (howMany > 0) {
$sections.eq(s).addClass('stuck');
howMany--;
}
else {
$sections.eq(s).removeClass('stuck');
}
}
}
// Helper function which builds the array sectionsInfo[] which keeps track of all the section elements
function buildSectionsInfo() {
// Build an array of the sections
// sectionsInfo[i][0] = Position from top of document
// sectionsInfo[i][1] = Height of section
// sectionsInfo[i][2] = Scroll offset (if taller than viewport)
var runningHeightCounter = 0,
viewportHeight = $(window).outerHeight(true);
for (var i = 0; i < $sections.length; i++) {
sectionsInfo[i] = [];
// record the height of the section
sectionsInfo[i][1] = $sections.eq(i).outerHeight(true);
// test this section height against viewport
if ( sectionsInfo[i][1] > viewportHeight ) {
sectionsInfo[i][2] = sectionsInfo[i][1] - viewportHeight;
$sections.eq(i).addClass('align-bottom');
}
else {
sectionsInfo[i][2] = 0;
$sections.eq(i).removeClass('align-bottom');
}
// write the data-scrollto
$sections.eq(i).attr('data-scrollto', $sections.eq(i).offset().top);
// if the section is stuck, calculate its .offset() based on preceeding section heights
if ( $sections.eq(i).hasClass('stuck') ) {
sectionsInfo[i][0] = runningHeightCounter;
runningHeightCounter += sectionsInfo[i][1];
}
else {
sectionsInfo[i][0] = $sections.eq(i).offset().top;
}
// Attach data attributes
$sections.eq(i)
.attr('data-scrollto', sectionsInfo[i][0])
.attr('data-height', sectionsInfo[i][1])
.attr('data-offset', sectionsInfo[i][2]);
}
}
};
// Default the defaults
$.fn.stickyStack.options = {
containerElement: '.main-content-wrapper',
stackingElement: 'section',
boxShadow: '0 -3px 20px rgba(0, 0, 0, 0.25)'
};
})(jQuery);