4
\$\begingroup\$

I have a "back to top"-button on the page, It should be visible after the user has scrolled a certain amount*.

This means I have to add or remove a class active every now and then.

I have two solutions:

  1. Update the class on every scroll.
  2. Test whether the class is set/ not et and then test, whether it is necessary to interact.

The setup:

this.button = document.querySelector('.some-class');

window.addEventListener('scroll', event => {
  this.onScroll(event);
});

The long version, which does add or remove the class only if needed:

onScroll(event) {
  if (
    !this.button.classList.contains('active') &&
    (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100)
  ) {
    this.button.classList.add('active');
  }

  if (
    this.button.classList.contains('active') &&
    (document.body.scrollTop <= 100 || document.documentElement.scrollTop <= 100)
  ) {
    this.button.classList.remove('is-active');
  }
}

The alternativ short version, that adds or removes the class everytime:

onScroll(event) {
  if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) {
    this.button.classList.add('active');
  } else {
    this.button.classList.remove('active');
  } 
}

My questions are:

  • Does the longer version have a better performance?
  • Does the browser optimize it itself – i.e. in the short version if the class is already present, it doesn't repaint?

* For simplicity this value is hard-coded here. It's a variable in the implemented version.

\$\endgroup\$
2
\$\begingroup\$

Does the longer version have a better performance?

No, the longer version has two different if conditions and you're recalculating the scroll area twice (i.e.: document.body.scrollTop > 100 || document.documentElement.scrollTop > 100 and document.body.scrollTop <= 100 || document.documentElement.scrollTop <= 100)


Does the browser optimize it itself – i.e. in the short version if the class is already present, it doesn't repaint?

Yes, if the class name already exists it'll simply be ignored.

classList MDN Documentation:

add( String [, String [, ...]] )

Adds the specified class values. If these classes already exist in the element's class attribute they are ignored.


Handling the scroll event can be performant heavy if you have a complex handler as the scroll event will be continuously fired during a scroll.

If you wish to optimize your scroll event handler, I would highly recommend using setTimeout. This allows your script to ONLY be called once the scroll has ended and skips doing your "heavy" condition checking for every scroll tick.

let setTimeoutId = null;
window.addEventListener('scroll', event => {
  //clear a previously pending timeout
  clearTimeout(setTimeoutId);
  //create a new timeout that will be launched in 400ms
  setTimeoutId = setTimeout(()=>onScroll(event), 100);
});

function onScroll(event){
  console.log("On scroll called");
}
body {
  height: 2000px;
  background-color: lightblue;
}

\$\endgroup\$
  • 1
    \$\begingroup\$ Thank you for pointing me into the right direction. For the last part: We already use a pipe|throttler|debouncer in our production code (depending on the project's framework). I just didn't wanted to bloat the question. \$\endgroup\$ – lampshade Jun 22 at 9:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.