andy
andy

Reputation: 2754

Add/remove class with jquery based on vertical scroll?

So basically I'd like to remove the class from 'header' after the user scrolls down a little and add another class to change it's look.

Trying to figure out the simplest way of doing this but I can't make it work.

$(window).scroll(function() {    
    var scroll = $(window).scrollTop();    
    if (scroll <= 500) {
        $(".clearheader").removeClass("clearHeader").addClass("darkHeader");
    }
}

CSS

.clearHeader{
    height: 200px; 
    background-color: rgba(107,107,107,0.66);
    position: fixed;
    top:200;
    width: 100%;   
}    

.darkHeader { height: 100px; }

.wrapper {
    height:2000px;
}

HTML

<header class="clearHeader">    </header>
<div class="wrapper">     </div>

I'm sure I'm doing something very elementary wrong.

Upvotes: 86

Views: 513819

Answers (8)

Be Kind
Be Kind

Reputation: 5182

Pure javascript

Here's javascript-only example of handling classes during scrolling.

//! Put the class name that you want to use
// Class name that will be added to the navbar element in the "scrolled" state
const SCROLLED_STATE_CLASS = "scrolled"

//! Use your own ID or selector
// The id of navigation bar HTML element
const NAVBAR_ID = "navbar"

// Get the navigation bar element
const navbar = document.getElementById(NAVBAR_ID)

// OnScroll event handler
const onScroll = () => {

  // Get scroll value
  const scroll = document.documentElement.scrollTop

  // If scroll value is more than 0 - means the page is scrolled, add or remove class based on that
  if (scroll > 0) {
    navbar.classList.add(SCROLLED_STATE_CLASS);
  } else {
    navbar.classList.remove(SCROLLED_STATE_CLASS)
  }
}

// Use the function
window.addEventListener('scroll', onScroll)
#navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: 60px;
  background-color: #89d0f7;
  box-shadow: 0px 5px 0px rgba(0, 0, 0, 0);
  transition: box-shadow 500ms;
}

#navbar.scrolled {
  box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.25);
}

#content {
  height: 3000px;
  margin-top: 60px;
}
<!-- Optional - lodash library, used for throttlin onScroll handler-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
<header id="navbar"></header>
<div id="content"></div>

Some improvements

You'd probably want to throttle handling scroll events, more so as handler logic gets more complex, in that case throttle from lodash lib comes in handy.

And if you're doing spa, keep in mind that you need to clear event listeners with removeEventListener once they're not needed (eg during onDestroy lifecycle hook of your component, like destroyed() for Vue, or maybe return function of useEffect hook for React).

Example throttling with lodash:

    // Throttling onScroll handler at 100ms with lodash
    const throttledOnScroll = _.throttle(onScroll, 100, {})

    // Use
    window.addEventListener('scroll', throttledOnScroll)

Upvotes: 9

Lodlaiden
Lodlaiden

Reputation: 391

This is based of of @shahzad-yousuf's answer, but I only needed to compress a menu when the user scrolled down. I used the reference point of the top container rolling "off screen" to initiate the "squish"

  <script type="text/javascript">
    $(document).ready(function (e) {
      //position of element
      var scroll_position = $('div.mainContainer').offset().top;
      var scroll_activation_point = scroll_position;
      $(window).on('scroll', function (e) {
        var y_scroll_pos = window.pageYOffset;
        var element_in_view = scroll_activation_point < y_scroll_pos;
        if (element_in_view) {
          $('body').addClass("toolbar-compressed ");
          $('div.toolbar').addClass("toolbar-compressed ");
        } else {
          $('body').removeClass("toolbar-compressed ");
          $('div.toolbar').removeClass("toolbar-compressed ");
        }
      });

    });   </script>

Upvotes: 0

chrisbergr
chrisbergr

Reputation: 198

In a similar case, I wanted to avoid always calling addClass or removeClass due to performance issues. I've split the scroll handler function into two individual functions, used according to the current state. I also added a debounce functionality according to this article: https://developers.google.com/web/fundamentals/performance/rendering/debounce-your-input-handlers

        var $header = jQuery( ".clearHeader" );         
        var appScroll = appScrollForward;
        var appScrollPosition = 0;
        var scheduledAnimationFrame = false;

        function appScrollReverse() {
            scheduledAnimationFrame = false;
            if ( appScrollPosition > 500 )
                return;
            $header.removeClass( "darkHeader" );
            appScroll = appScrollForward;
        }

        function appScrollForward() {
            scheduledAnimationFrame = false;
            if ( appScrollPosition < 500 )
                return;
            $header.addClass( "darkHeader" );
            appScroll = appScrollReverse;
        }

        function appScrollHandler() {
            appScrollPosition = window.pageYOffset;
            if ( scheduledAnimationFrame )
                return;
            scheduledAnimationFrame = true;
            requestAnimationFrame( appScroll );
        }

        jQuery( window ).scroll( appScrollHandler );

Maybe someone finds this helpful.

Upvotes: 1

user9261696
user9261696

Reputation: 21

For Android mobile $(window).scroll(function() and $(document).scroll(function() may or may not work. So instead use the following.

jQuery(document.body).scroll(function() {
        var scroll = jQuery(document.body).scrollTop();

        if (scroll >= 300) {
            //alert();
            header.addClass("sticky");
        } else {
            header.removeClass('sticky');
        }
    });

This code worked for me. Hope it will help you.

Upvotes: 2

Shahzad Yousuf
Shahzad Yousuf

Reputation: 41

Its my code

jQuery(document).ready(function(e) {
    var WindowHeight = jQuery(window).height();

    var load_element = 0;

    //position of element
    var scroll_position = jQuery('.product-bottom').offset().top;

    var screen_height = jQuery(window).height();
    var activation_offset = 0;
    var max_scroll_height = jQuery('body').height() + screen_height;

    var scroll_activation_point = scroll_position - (screen_height * activation_offset);

    jQuery(window).on('scroll', function(e) {

        var y_scroll_pos = window.pageYOffset;
        var element_in_view = y_scroll_pos > scroll_activation_point;
        var has_reached_bottom_of_page = max_scroll_height <= y_scroll_pos && !element_in_view;

        if (element_in_view || has_reached_bottom_of_page) {
            jQuery('.product-bottom').addClass("change");
        } else {
            jQuery('.product-bottom').removeClass("change");
        }

    });

});

Its working Fine

Upvotes: 4

Marc
Marc

Reputation: 41

Add some transition effect to it if you like:

http://jsbin.com/boreme/17/edit?html,css,js

.clearHeader {
  height:50px;
  background:lightblue;
  position:fixed;
  top:0;
  left:0;
  width:100%;

  -webkit-transition: background 2s; /* For Safari 3.1 to 6.0 */
  transition: background 2s;
}

.clearHeader.darkHeader {
 background:#000;
}

Upvotes: 4

Fabr&#237;cio Matt&#233;
Fabr&#237;cio Matt&#233;

Reputation: 70149

$(window).scroll(function() {    
    var scroll = $(window).scrollTop();

     //>=, not <=
    if (scroll >= 500) {
        //clearHeader, not clearheader - caps H
        $(".clearHeader").addClass("darkHeader");
    }
}); //missing );

Fiddle

Also, by removing the clearHeader class, you're removing the position:fixed; from the element as well as the ability of re-selecting it through the $(".clearHeader") selector. I'd suggest not removing that class and adding a new CSS class on top of it for styling purposes.

And if you want to "reset" the class addition when the users scrolls back up:

$(window).scroll(function() {    
    var scroll = $(window).scrollTop();

    if (scroll >= 500) {
        $(".clearHeader").addClass("darkHeader");
    } else {
        $(".clearHeader").removeClass("darkHeader");
    }
});

Fiddle

edit: Here's version caching the header selector - better performance as it won't query the DOM every time you scroll and you can safely remove/add any class to the header element without losing the reference:

$(function() {
    //caches a jQuery object containing the header element
    var header = $(".clearHeader");
    $(window).scroll(function() {
        var scroll = $(window).scrollTop();

        if (scroll >= 500) {
            header.removeClass('clearHeader').addClass("darkHeader");
        } else {
            header.removeClass("darkHeader").addClass('clearHeader');
        }
    });
});

Fiddle

Upvotes: 223

ido
ido

Reputation: 811

Is this value intended? if (scroll <= 500) { ... This means it's happening from 0 to 500, and not 500 and greater. In the original post you said "after the user scrolls down a little"

Upvotes: 1

Related Questions