jquery.sticky.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Sticky Plugin v1.0.2 for jQuery
  2. // =============
  3. // Author: Anthony Garand
  4. // Improvements by German M. Bravo (Kronuz) and Ruud Kamphuis (ruudk)
  5. // Improvements by Leonardo C. Daronco (daronco)
  6. // Created: 2/14/2011
  7. // Date: 16/04/2015
  8. // Website: http://labs.anthonygarand.com/sticky
  9. // Description: Makes an element on the page stick on the screen as you scroll
  10. // It will only set the 'top' and 'position' of your element, you
  11. // might need to adjust the width in some cases.
  12. (function($) {
  13. var slice = Array.prototype.slice; // save ref to original slice()
  14. var splice = Array.prototype.splice; // save ref to original slice()
  15. var defaults = {
  16. topSpacing: 0,
  17. bottomSpacing: 0,
  18. className: 'is-sticky',
  19. wrapperClassName: 'sticky-wrapper',
  20. center: false,
  21. getWidthFrom: '',
  22. widthFromWrapper: true, // works only when .getWidthFrom is empty
  23. responsiveWidth: false
  24. },
  25. $window = $(window),
  26. $document = $(document),
  27. sticked = [],
  28. windowHeight = $window.height(),
  29. scroller = function() {
  30. var scrollTop = $window.scrollTop(),
  31. documentHeight = $document.height(),
  32. dwh = documentHeight - windowHeight,
  33. extra = (scrollTop > dwh) ? dwh - scrollTop : 0;
  34. for (var i = 0; i < sticked.length; i++) {
  35. var s = sticked[i],
  36. elementTop = s.stickyWrapper.offset().top,
  37. etse = elementTop - s.topSpacing - extra;
  38. if (scrollTop <= etse) {
  39. if (s.currentTop !== null) {
  40. s.stickyElement
  41. .css({
  42. 'width': '',
  43. 'position': '',
  44. 'top': ''
  45. });
  46. s.stickyElement.parent().removeClass(s.className);
  47. s.stickyElement.trigger('sticky-end', [s]);
  48. s.currentTop = null;
  49. }
  50. }
  51. else {
  52. var newTop = documentHeight - s.stickyElement.outerHeight()
  53. - s.topSpacing - s.bottomSpacing - scrollTop - extra;
  54. if (newTop < 0) {
  55. newTop = newTop + s.topSpacing;
  56. } else {
  57. newTop = s.topSpacing;
  58. }
  59. if (s.currentTop != newTop) {
  60. var newWidth;
  61. if ( s.getWidthFrom ) {
  62. newWidth = $(s.getWidthFrom).width() || null;
  63. }
  64. else if(s.widthFromWrapper) {
  65. newWidth = s.stickyWrapper.width();
  66. }
  67. if ( newWidth == null ) {
  68. newWidth = s.stickyElement.width();
  69. }
  70. s.stickyElement
  71. .css('width', newWidth)
  72. .css('position', 'fixed')
  73. .css('top', newTop);
  74. s.stickyElement.parent().addClass(s.className);
  75. if (s.currentTop === null) {
  76. s.stickyElement.trigger('sticky-start', [s]);
  77. } else {
  78. // sticky is started but it have to be repositioned
  79. s.stickyElement.trigger('sticky-update', [s]);
  80. }
  81. if (s.currentTop === s.topSpacing && s.currentTop > newTop || s.currentTop === null && newTop < s.topSpacing) {
  82. // just reached bottom || just started to stick but bottom is already reached
  83. s.stickyElement.trigger('sticky-bottom-reached', [s]);
  84. } else if(s.currentTop !== null && newTop === s.topSpacing && s.currentTop < newTop) {
  85. // sticky is started && sticked at topSpacing && overflowing from top just finished
  86. s.stickyElement.trigger('sticky-bottom-unreached', [s]);
  87. }
  88. s.currentTop = newTop;
  89. }
  90. }
  91. }
  92. },
  93. resizer = function() {
  94. windowHeight = $window.height();
  95. for (var i = 0; i < sticked.length; i++) {
  96. var s = sticked[i];
  97. var newWidth = null;
  98. if ( s.getWidthFrom ) {
  99. if ( s.responsiveWidth === true ) {
  100. newWidth = $(s.getWidthFrom).width();
  101. }
  102. }
  103. else if(s.widthFromWrapper) {
  104. newWidth = s.stickyWrapper.width();
  105. }
  106. if ( newWidth != null ) {
  107. s.stickyElement.css('width', newWidth);
  108. }
  109. }
  110. },
  111. methods = {
  112. init: function(options) {
  113. var o = $.extend({}, defaults, options);
  114. return this.each(function() {
  115. var stickyElement = $(this);
  116. var stickyId = stickyElement.attr('id');
  117. var stickyHeight = stickyElement.outerHeight();
  118. var wrapperId = stickyId ? stickyId + '-' + defaults.wrapperClassName : defaults.wrapperClassName
  119. var wrapper = $('<div></div>')
  120. .attr('id', wrapperId)
  121. .addClass(o.wrapperClassName);
  122. stickyElement.wrapAll(wrapper);
  123. var stickyWrapper = stickyElement.parent();
  124. if (o.center) {
  125. stickyWrapper.css({width:stickyElement.outerWidth(),marginLeft:"auto",marginRight:"auto"});
  126. }
  127. if (stickyElement.css("float") == "right") {
  128. stickyElement.css({"float":"none"}).parent().css({"float":"right"});
  129. }
  130. stickyWrapper.css('height', stickyHeight);
  131. o.stickyElement = stickyElement;
  132. o.stickyWrapper = stickyWrapper;
  133. o.currentTop = null;
  134. sticked.push(o);
  135. });
  136. },
  137. update: scroller,
  138. unstick: function(options) {
  139. return this.each(function() {
  140. var that = this;
  141. var unstickyElement = $(that);
  142. var removeIdx = -1;
  143. var i = sticked.length;
  144. while ( i-- > 0 )
  145. {
  146. if (sticked[i].stickyElement.get(0) === that)
  147. {
  148. splice.call(sticked,i,1);
  149. removeIdx = i;
  150. }
  151. }
  152. if(removeIdx != -1)
  153. {
  154. unstickyElement.unwrap();
  155. unstickyElement
  156. .css({
  157. 'width': '',
  158. 'position': '',
  159. 'top': '',
  160. 'float': ''
  161. })
  162. ;
  163. }
  164. });
  165. }
  166. };
  167. // should be more efficient than using $window.scroll(scroller) and $window.resize(resizer):
  168. if (window.addEventListener) {
  169. window.addEventListener('scroll', scroller, false);
  170. window.addEventListener('resize', resizer, false);
  171. } else if (window.attachEvent) {
  172. window.attachEvent('onscroll', scroller);
  173. window.attachEvent('onresize', resizer);
  174. }
  175. $.fn.sticky = function(method) {
  176. if (methods[method]) {
  177. return methods[method].apply(this, slice.call(arguments, 1));
  178. } else if (typeof method === 'object' || !method ) {
  179. return methods.init.apply( this, arguments );
  180. } else {
  181. $.error('Method ' + method + ' does not exist on jQuery.sticky');
  182. }
  183. };
  184. $.fn.unstick = function(method) {
  185. if (methods[method]) {
  186. return methods[method].apply(this, slice.call(arguments, 1));
  187. } else if (typeof method === 'object' || !method ) {
  188. return methods.unstick.apply( this, arguments );
  189. } else {
  190. $.error('Method ' + method + ' does not exist on jQuery.sticky');
  191. }
  192. };
  193. $(function() {
  194. setTimeout(scroller, 0);
  195. });
  196. })(jQuery);