1

I'm trying to create a jQuery snippet that enables me to add 4 different classes to a div based on the user's current scroll position.

The desired states are: 1. User is at top of page 2. User is at bottom of page 3. User is scrolling down 4. User is scrolling up

In the below code I have achieved number 1 & 2, but am not able to get 3 & 4 to work.

Can anybody help? Thanks.

// Add/remove classes to navigation based on position
var scrollPosition = $(window).scrollTop();

$(window).bind( 'load scroll', function(){

    // User is at bottom of window
    if($(window).scrollTop() + $(window).height() === $(document).height()) {
       $('#global-header').removeClass().addClass('at-bottom');
    // User is at top of window
    } else if ($(window).scrollTop() === 0) {
        $('#global-header').removeClass().addClass('at-top');
    } else {
        $('#global-header').removeClass();
    }
});
dungey_140
  • 2,602
  • 7
  • 34
  • 68
  • #3 and #4 would involve capturing the previous scroll position, preserving it between scroll events, and comparing it to the new scroll position to know the direction. – Taplar Apr 19 '18 at 20:14
  • possible duplicate of https://stackoverflow.com/questions/9144560/jquery-scroll-detect-when-user-stops-scrolling – Bonnie Apr 19 '18 at 20:14
  • @Taplar - can you assist with this at all? – dungey_140 Apr 19 '18 at 20:15

2 Answers2

1

Here you have a working solution capturing the previous solution (as suggested in the comments by @Taplar):

// Add/remove classes to navigation based on position
var scrollPosition = $(window).scrollTop();

var threshold = 12;
var hideHeaderOnScrollDelay = 200;
var lastScrollPosition = 0;
$(window).bind('load scroll', function() {

  // User is at bottom of window
  if ($(window).scrollTop() + $(window).height() >= $(document).height()) {
    $('#global-header').removeClass().addClass('at-bottom');
    // User is at top of window
  } else if ($(window).scrollTop() === 0) {
    $('#global-header').removeClass().addClass('at-top');
  } else {
    if ($(window).scrollTop() - lastScrollPosition > threshold) {
      $('#global-header').removeClass().addClass('at-bottom');
    } else if (lastScrollPosition - $(window).scrollTop() > threshold) {
      $('#global-header').removeClass().addClass('at-top');
    }
  }

  lastScrollPosition = $(window).scrollTop();
});
#global-header {
  position: fixed;
  width: 100%;
  height: 60px;
  background-color: #006688;
  color: white;
  text-align: center;
  line-height: 60px;
  display: none;
}

#global-header.at-top,
#global-header.at-bottom {
  display: block;
}

#global-header.at-bottom {
  bottom: 0px;
}

#content {
  height: 600px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<div id="global-header">HEADER</div>

<div id="content"></div>
raul.vila
  • 1,984
  • 1
  • 11
  • 24
  • Thanks so much for this, works well! I have simplified to suit my question, as I don't require the automatic hiding of the header. I also want to retain the classes until another class becomes active. Thanks! – dungey_140 Apr 19 '18 at 21:16
  • Hi @raul.vila - In my answer, are you able to explain exactly what the var lastScrollPosition = 0; and lastScrollPosition = $(window).scrollTop(); are doing? I'd like to explain exactly what purpose they serve, although I know they are required. Thank you! – dungey_140 Apr 19 '18 at 21:22
  • @dungey_140 It's a [simple way to detect the scrolling direction](https://stackoverflow.com/questions/31223341/detecting-scroll-direction). The scrolling event has no info about it (the wheel event does, but that doesn't work with cursor or pageUp/pageDown navigation) so you can compare the current position with the previous one to see where the user is going. The first initialization to `0` is because the page is loaded at top (anyway the value is set when again `load` event is fired), and then we keep its value updated after each scroll event. – raul.vila Apr 19 '18 at 21:35
  • @dungey_140 I've updated my answer and removed the `setTimeout` so it matches your requirements. Feel free to mark as solved if that's the case. – raul.vila Apr 19 '18 at 21:35
  • One final thought, could it be possible to add a 'scroll threshold' to only activate the scrolling-up and scrolling-down classes if the user has scrolled more than 100px? – dungey_140 Apr 19 '18 at 22:35
  • @dungey I've updated the answer with `if ($(window).scrollTop() - lastScrollPosition > threshold) { ... } else if (lastScrollPosition - $(window).scrollTop() > threshold) { ... }` which work for me but I would not assume the behavior will be consistent between different browsers and envirtonment configurations. – raul.vila Apr 19 '18 at 22:45
  • @dungey_140 Yes it is. – raul.vila Apr 20 '18 at 07:47
1

Thanks to @raul.vila for his working solution. This answer is a simplified version with the purpose of adding 4 classes, .at-top, .at-bottom, .scrolling-up and .scrolling-down. It also retains these classes until such point as another class becomes active.

// Add/remove classes to navigation based on position
var lastScrollPosition = 0;

$(window).bind('load scroll', function() {
    // User is at top of window
    if ($(window).scrollTop() === 0) {
        $('#global-header').removeClass().addClass('at-top');
    // User is at bottom of window
    } else if ($(window).scrollTop() + $(window).height() >= $(document).height()) {
        $('#global-header').removeClass().addClass('at-bottom');
    // User is scrolling down
    } else if (lastScrollPosition < $(window).scrollTop()) {
        $('#global-header').removeClass().addClass('scrolling-down');
    // User is scrolling up
    } else {
        $('#global-header').removeClass().addClass('scrolling-up');
    }

    lastScrollPosition = $(window).scrollTop();
});
dungey_140
  • 2,602
  • 7
  • 34
  • 68