0

I have a minimalist transparent header with just the hamburger on the left and the logo in the centre. The hamburger icon and the logo include transparency so my intention is to have them be black when the content below is light and white when the content below is dark. (I'm using an SVG suitable for styling with css).

Using jQuery, the logic I'm working on is to collect all appropriately classed sections and on scroll, cycle backwards through them checking if the section.top value is lower than the scrollTop() value. If it is then since we are going backwards, this is the section currently under the header so apply/remove a class to the header to control the colour of the header elements and then stop going through the sections because we don't want any others to change the colour again.

The code I came up with is...

jQuery(function($) {

  var $sections = $('.content_section').get().reverse();
  if ($sections.length > 0) {      

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

      $sections.each(function() { 
        var sectionPos = $(this).offset();        

        if ( scrollPos >= sectionPos.top() ) {
        
          if ($(this).hasClass("dark_section")) {
            $('header').addClass('dark_section_below');
          } else {
            $('header').removeClass('dark_section_below');
          }
          
          return false;

        }
      });
    });
  }
});

But console is telling me $sections.each is not a function. Before the code goes in to the .scroll() function, $sections is a jQuery object and $sections.each() works fine. Clearly I'm tripping up on scope or something here, but I thought my $sections would be global?

Any help you can give me fixing this is very much appreciated. If you have different/better way to do what I'm trying to achieve here, I'd love to see that too.

Baddie
  • 305
  • 1
  • 3
  • 11
  • A different way might be to use IntersectionObserver on the sections to sense when they come up to the header as it might save on having to listen for scroll all the time. – A Haworth Apr 28 '21 at 11:34
  • I noticed I made an error in my OP... `sectionPos.top()` should read `sectionPos.top` – Baddie Apr 28 '21 at 12:17

1 Answers1

1

var $sections = $('.content_section').get().reverse();

This returns JavaScript array, so you need to wrap it around jQuery function $() to use the jQuery each method on it and then it would iterate fine.

$($sections).each(function() {

jQuery(function($) {

  var $sections = $('.content_section').get().reverse();
  if ($sections.length > 0) {      

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

      $($sections).each(function() { 
        var sectionPos = $(this).offset();        

        if ( scrollPos >= sectionPos.top() ) {
        
          if ($(this).hasClass("dark_section")) {
            $('header').addClass('dark_section_below');
          } else {
            $('header').removeClass('dark_section_below');
          }
          
          return false;

        }
      });
    });
  }
});

Link for reference:

JQuery .each() backwards

Chitrang
  • 2,079
  • 1
  • 16
  • 18
  • Excellent. That was exactly the problem and it iterated fine just as you said. Thank you so much!! Note: for anyone else reading, I noticed I made an error in my original code and `sectionPos.top()` should read `sectionPos.top` – Baddie Apr 28 '21 at 12:17
  • Glad to help..! – Chitrang Apr 28 '21 at 12:55