forked from pixelthing/fixed-sticky
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfixedsticky.js
119 lines (104 loc) · 3.1 KB
/
fixedsticky.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
;(function( win, $ ) {
function featureTest( property, value, noPrefixes ) {
// Thanks Modernizr! https://github.com/phistuck/Modernizr/commit/3fb7217f5f8274e2f11fe6cfeda7cfaf9948a1f5
var prop = property + ':',
el = document.createElement( 'test' ),
mStyle = el.style;
if( !noPrefixes ) {
mStyle.cssText = prop + [ '-webkit-', '-moz-', '-ms-', '-o-', '' ].join( value + ';' + prop ) + value + ';';
} else {
mStyle.cssText = prop + value;
}
return mStyle[ property ].indexOf( value ) !== -1;
}
var S = {
classes: {
plugin: 'fixedsticky',
active: 'fixedsticky-on',
clone: 'fixedsticky-dummy',
withoutFixedFixed: 'fixedsticky-withoutfixedfixed'
},
tests: {
sticky: featureTest( 'position', 'sticky' ),
fixed: featureTest( 'position', 'fixed', true )
},
// Thanks jQuery!
getScrollTop: function() {
var prop = 'pageYOffset',
method = 'scrollTop';
return win ? (prop in win) ? win[ prop ] :
win.document.documentElement[ method ] :
win.document.body[ method ];
},
update: function( el ) {
// Only exec if native sticky isn’t supported, fixed is supported,
// and if fixed-fixed is also included on the page and is supported
if( S.tests.sticky || !S.tests.fixed || win.FixedFixed && !$( win.document.documentElement ).hasClass( 'fixed-supported' ) ) {
return;
}
if( !el.offsetWidth ) {
return;
}
var $el = $( el ),
keys = {
offset: 'fixedStickyOffset',
position: 'fixedStickyPosition'
},
height = $el.outerHeight(),
initialOffset = $el.data( keys.offset ),
scroll = S.getScrollTop(),
isAlreadyOn = $el.is( '.' + S.classes.active ),
toggle = function( turnOn ) {
$el[ turnOn ? 'addClass' : 'removeClass' ]( S.classes.active );
},
viewportHeight = $( window ).height(),
position = $el.data( keys.position ) || {
top: false,
bottom: false
};
if( !initialOffset ) {
initialOffset = $el.offset().top;
$el.data( keys.offset, initialOffset );
$el.after( $( '<div>' ).addClass( S.classes.clone ).height( height ) );
$el.css( 'position', 'fixed' );
position.top = $el.css( 'top' ) !== 'auto';
position.bottom = $el.css( 'bottom' ) !== 'auto';
$el.css( 'position', '' );
$el.data( keys.position, position );
}
if( position.top && initialOffset < scroll ||
position.bottom && initialOffset > scroll + viewportHeight - ( height || 0 ) ) {
if( !isAlreadyOn ) {
toggle( true );
}
} else {
if( isAlreadyOn ) {
toggle( false );
}
}
},
init: function( el ) {
var $el = $( el );
$( win ).bind( 'scroll', function() {
S.update( el );
}).trigger( 'scroll' );
$( win ).bind( 'resize', function() {
if( $el.is( '.' + S.classes.active ) ) {
S.update( el );
}
});
}
};
// Expose Global
win.FixedSticky = S;
// Plugin
$.fn.fixedsticky = function(){
return this.each(function () {
S.init( this );
});
};
// Add fallback when fixed-fixed is not available.
if( !win.FixedFixed ) {
$( win.document.documentElement ).addClass( S.classes.withoutFixedFixed );
}
})( this, jQuery );