Home > Software engineering >  Add 'is-page-scrolled' class on vertical scroll with pure JavaScript
Add 'is-page-scrolled' class on vertical scroll with pure JavaScript

Time:11-28

I'm trying to migrate some jQuery code to pure JavaScript. The current jQuery code toggles a class named is-page-scrolled in the body element when the user scrolls down to a specific offset set in a data attribute in the body element named data-page-scrolled-offset. If the user scrolls up again to the top of the page, the class is toggled off.

My working jQuery code:

var scrolled_page_offset = parseInt( $( 'body' ).data( 'pageScrolledOffset' ) );
var scrolled_page = function() {
    var scroll_top = window.pageYOffset;
    $( 'body' ).toggleClass( 'is-page-scrolled', scroll_top > scrolled_page_offset );
};

$( window ).on( 'scroll', function() {
    scrolled_page();
} );

scrolled_page();

My non-working pure JavaScript code:

var scrolled_page_offset = parseInt( document.body.dataset.pageScrolledOffset );
var scrolled_page = function() {
    var scroll_top = window.pageYOffset;
    if ( scroll_top > scrolled_page_offset ) {
        document.body.classList.toggle( 'is-page-scrolled' );
    }
};

window.addEventListener( 'scroll', function() {
    scrolled_page();
} );

scrolled_page();

My proposed pure Javascript code is not working as expected because it toggles the class on and off intermittently when the user scrolls down in the page.

What am I doing wrong?

CodePudding user response:

Explanation of the current problem, copied from my comment:

jQuery's toggleClass() is setting the class on/off based on the scroll_top > scrolled_page_offset. Your if toggle() is inverting the on/off state of the class every time scroll_top > scrolled_page_offset is true.

If we compare "does the class exist" to "do we want the class to exist", we avoid accidentally inverting the state of the class.

If this example I've added:

  const isEnabled = document.body.classList.contains(className)
  const shouldBeEnabled = scroll_top > scrolled_page_offset
  if (shouldBeEnabled !== isEnabled) { ... }

Which will only run the if when we expect the class to change.

(In this demo, the background turns green to show when the class is added)

// Set up the demo, ignore this
document.body.dataset.pageScrolledOffset = 200;
//

const className = 'is-page-scrolled'
const scrolled_page_offset = parseInt(document.body.dataset.pageScrolledOffset);
const scrolled_page = function() {
  const scroll_top = window.pageYOffset;

  const isEnabled = document.body.classList.contains(className)
  const shouldBeEnabled = scroll_top > scrolled_page_offset

  if (shouldBeEnabled !== isEnabled) {
    document.body.classList.toggle(className);
  }
};

window.addEventListener('scroll', function() {
  scrolled_page();
});
scrolled_page();
#scrollable {
  height: 10000px;
}

.is-page-scrolled {
  background: #060;
}
<div id="scrollable">
  Scroll down
</div>

  • Related