scrollpos-styler.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. /* ========================================================================
  2. * ScrollPos-Styler v0.7.0
  3. * https://github.com/acch/scrollpos-styler
  4. * ========================================================================
  5. * Copyright 2015 Achim Christ
  6. * Licensed under MIT (https://github.com/acch/scrollpos-styler/blob/master/LICENSE)
  7. * ======================================================================== */
  8. // JSHint directives
  9. /* exported ScrollPosStyler */
  10. var ScrollPosStyler = (function(document, window) {
  11. "use strict";
  12. /* ====================
  13. * private variables
  14. * ==================== */
  15. var scrollPosY = 0,
  16. busy = false,
  17. // toggle style / class when scrolling below this position (in px)
  18. scrollOffsetY = 1,
  19. // class used to apply scrollPosStyler to
  20. spsClass = "sps",
  21. // choose elements to apply style / class to
  22. elements = document.getElementsByClassName(spsClass),
  23. // style / class to apply to elements when above scroll position
  24. classAbove = "sps--abv",
  25. // style / class to apply to elements when below scroll position
  26. classBelow = "sps--blw",
  27. // tag to set custom scroll offset per element
  28. offsetTag = "data-sps-offset";
  29. /* ====================
  30. * private funcion to check scroll position
  31. * ==================== */
  32. function onScroll() {
  33. // ensure that events don't stack
  34. if (!busy) {
  35. // find elements to update
  36. var elementsToUpdate = getElementsToUpdate();
  37. if (elementsToUpdate.length > 0) {
  38. // suspend accepting scroll events
  39. busy = true;
  40. // asynchronuously update elements
  41. window.requestAnimationFrame(function() {
  42. updateElements(elementsToUpdate);
  43. });
  44. }
  45. }
  46. }
  47. /* ====================
  48. * private funcion to find elements to update
  49. * ==================== */
  50. function getElementsToUpdate() {
  51. // get current scroll position from window
  52. scrollPosY = window.pageYOffset;
  53. var elementsToUpdate = [];
  54. // iterate over elements
  55. // for (var elem of elements) {
  56. for (var i = 0; elements[i]; ++i) { // chrome workaround
  57. var element = elements[i];
  58. // get offset from element, default to global option
  59. var elScrollOffsetY = element.getAttribute(offsetTag) || scrollOffsetY;
  60. // check current state of element
  61. var elOnTop = element.classList.contains(classAbove);
  62. // if we were above, and are now below scroll position...
  63. if (elOnTop && scrollPosY > elScrollOffsetY) {
  64. // remember element
  65. elementsToUpdate.push({
  66. element: element,
  67. addClass: classBelow,
  68. removeClass: classAbove
  69. });
  70. // if we were below, and are now above scroll position...
  71. } else if (!elOnTop && scrollPosY <= elScrollOffsetY) {
  72. // remember element
  73. elementsToUpdate.push({
  74. element: element,
  75. addClass: classAbove,
  76. removeClass: classBelow
  77. });
  78. }
  79. }
  80. return elementsToUpdate;
  81. }
  82. /* ====================
  83. * private funcion to update elements
  84. * ==================== */
  85. function updateElements(elementsToUpdate) {
  86. // iterate over elements
  87. // for (var elem of elements) {
  88. for (var i = 0; elementsToUpdate[i]; ++i) { // chrome workaround
  89. var map = elementsToUpdate[i];
  90. // add style / class to element
  91. map.element.classList.add(map.addClass);
  92. map.element.classList.remove(map.removeClass);
  93. }
  94. // resume accepting scroll events
  95. busy = false;
  96. }
  97. /* ====================
  98. * public function to initially style elements based on scroll position
  99. *
  100. * Options:
  101. * scrollOffsetY (number): Default scroll position in px to trigger the style. Default is 1.
  102. * spsClass (String): Classname used to determine which elements to style. Default is 'sps'.
  103. * classAbove (String): Classname added to the elements when the window is scrolled above the defined position. Default is 'sps--abv'.
  104. * classBelow (String): Classname added to the elements when the window is scrolled below the defined position. Default is 'sps--blw'.
  105. * offsetTag (String): HTML tag used on the element to specify a scrollOffsetY other than the default.
  106. *
  107. * ==================== */
  108. var pub = {
  109. init: function(options) {
  110. // suspend accepting scroll events
  111. busy = true;
  112. // merge options object with global options
  113. if (options) {
  114. if (options.spsClass) {
  115. spsClass = options.spsClass;
  116. elements = document.getElementsByClassName(spsClass);
  117. }
  118. scrollOffsetY = options.scrollOffsetY || scrollOffsetY;
  119. classAbove = options.classAbove || classAbove;
  120. classBelow = options.classBelow || classBelow;
  121. offsetTag = options.offsetTag || offsetTag;
  122. }
  123. // find elements to update
  124. var elementsToUpdate = getElementsToUpdate();
  125. if (elementsToUpdate.length > 0) {
  126. // asynchronuously update elements
  127. window.requestAnimationFrame(function() {
  128. updateElements(elementsToUpdate);
  129. });
  130. } else {
  131. // resume accepting scroll events
  132. busy = false;
  133. }
  134. }
  135. };
  136. /* ====================
  137. * main initialization
  138. * ==================== */
  139. // add initial style / class to elements when DOM is ready
  140. document.addEventListener("DOMContentLoaded", function() {
  141. // defer initialization to allow browser to restore scroll position
  142. window.setTimeout(pub.init, 1);
  143. });
  144. // register for window scroll events
  145. window.addEventListener("scroll", onScroll);
  146. return pub;
  147. })(document, window);