# Adding and removing classes at different heights on page using jQuery

I want to remove/add classes when the user is at different distances from the top by using jQuery.

I have successfully done it, and it works fine, but I think I'm doing it wrong, and I would like your help to optimize the code.

The html is simple, basically the sections(including the header), have 100% width. and different colors. I want to make the header change color when its over the first section(for aesthetical purposes). And I also want it to have a shadow when the page has been scrolled more than 1 pixel.

I'm doing it by adding/removing classes.

When I use one big else if statement it doesn't work well because whenever any any condition is matched js stops checking for other matches, so it doesn't apply all the classes needed.

The next code works, however as I said, I think that it's not optimal/badly written. Here is the HTML markup:

<header class="dark no-shadow">
<section class="blue">
Please Scroll Down to see the header changes...
</section>
<section>
The header color Should change when you pass through me.
</section>


And here is the jQuery code:

var header = $('header'), blueSection =$('section.blue'),
// Calculate when to change the color.
offset = blueSection.offset().top + blueSection.height() - header.height();

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

// Remove Class "dark" after scrolling over the dark section
if (scroll >= offset) {
} else {
}

// Remove Class "no-shadows" whenever not on the top of the page.
if (scroll >= 1) {
} else {
}

});


And for those of you who like to use JSFiddle(like me!): https://jsfiddle.net/shock/wztdt077/6/

I know you tagged this jQuery, but I believe that loading in jQuery for this seems like a lot of processing for little benefit, so I decided to write it in a more universal approach, which I think is the main problem with your code.

What you want to accomplish is to have a little script that can be included and will work predictably in as many circumstances without being to specific, so first I went about actually creating a structure:

• The element the class will be applied to will have an attribute named data-scroll-group - it will define the group name for these scrollable items.
• The elements that your header will respond to will contain an attribute constructed of the above group name and prefixed by data. It's contents will be the classname(s) you want to apply.

This structure looks like this:

<header data-scroll-group="header-group"></header>


This means you could have many scroll groups on the page, allowing you to reuse the code with different aspect and different headers, different responders, etc... It makes your code less connected to the DOM and more based in a structure.

The rest is pretty simple. Use getBoundingClientRect to get the elements position compared to the viewport. I am currently applying the classes using the position of the viewport, but you could simply get the same getBoundingClientRect on the header and add the values together to get a result for your header specifically.

Check out the snippet and tell me if you have any questions about it. You could replace my header.className with jQuery if you wanted - you could replace most of it with jQuery, but I think coupling your code to jQuery has no benefit here, as you want this to work anywhere, and pure vanilla Javascript is about as long.

// This is a handy wrapper function that will return an array of matching element instead of a nodeList
function querySelectorArray(query, root){
return Array.prototype.slice.call((root || document).querySelectorAll(query));
}

// Get all headers that are designated 'scroll-group'
var headers = querySelectorArray('[data-scroll-group]');

// Loop through the headers
// Get the name of the group from the headers [data-scroll-group] attribute
var group = header.getAttribute('data-scroll-group');
// Get all the sections with a matching data-[data-scroll-group] attribute
var sections = querySelectorArray('[data-' + group + ']');
// Create an Event Listener for scrolling
// Declare a lastSection variable that can store the last class that scrolled by
var lastSection = false;
sections.forEach(function(section){
// Get the elements position compared to the viewport
var offset = section.getBoundingClientRect();
// If the position is smaller than 0 it has scrolled further than that section
// The same is true for the scroll being smaller than the negative height - if so, it is out of view.
if(offset.top < 0 && offset.top > -offset.height) lastSection = section.getAttribute('data-' + group + '');
});
// Apply the class to your header
header.className = lastSection || '';
})
});
body {
margin: 0;
height: 405vh;
font-family: Arial, serif;
}
position: fixed;
width: 100%;
top: 0;
left: 0;
background: #dd0300;
-webkit-transition: all 1s;
transition: all 1s;
color: #fff;
box-sizing: border-box;
}
background: #4e88ff;
}
box-shadow: 0 0 20px #000;
}
section {
box-sizing: border-box;
width: 100%;
height: 100vh;
background: #ccc;
}
<header data-scroll-group="header-group">
</section>