Add/remove class with jquery based on vertical scroll?

JavascriptJqueryCss

Javascript Problem Overview


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.

Javascript Solutions


Solution 1 - Javascript

$(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

Solution 2 - Javascript

Pure javascript

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

const navbar = document.getElementById('navbar')

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

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

  // If scroll value is more than 0 - add class
  if (scroll > 0) {
    navbar.classList.add("scrolled");
  } else {
    navbar.classList.remove("scrolled")
  }
}

// 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)

Solution 3 - Javascript

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;
}

Solution 4 - Javascript

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

Solution 5 - Javascript

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"

Solution 6 - Javascript

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.

Solution 7 - Javascript

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.

Solution 8 - Javascript

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>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionandyView Question on Stackoverflow
Solution 1 - JavascriptFabrício MattéView Answer on Stackoverflow
Solution 2 - JavascriptegoView Answer on Stackoverflow
Solution 3 - JavascriptMarcView Answer on Stackoverflow
Solution 4 - JavascriptShahzad YousufView Answer on Stackoverflow
Solution 5 - JavascriptidoView Answer on Stackoverflow
Solution 6 - JavascriptchrisbergrView Answer on Stackoverflow
Solution 7 - Javascriptuser9261696View Answer on Stackoverflow
Solution 8 - JavascriptLodlaidenView Answer on Stackoverflow