Browser scrollbar, position fixed, dropdown menu, and jumps

·

1 min read

Firstly, let's see a small problem:

This is our situation:

  • I am using @radix-ui/themes for all the components;

  • The header is fixed positioned;

  • When the dropdown menu opens, it adds an overlay, which hides the scrollbar;

  • So the header's width is bigger, then it moves to right a bit;

  • If you observe it carefully, the image also moves a bit;

It's not a big problem, but we can fix it.

The idea is, always set the header's width to be window width - scrollbar width, no matter there is scrollbar or not.

But how to calculate the width of the scrollbar? Different browsers have different scrollbars.

Easy. See this:

function getScrollbarWidth() {
  const scrollDiv = document.createElement('div');
  scrollDiv.style.width = '100px';
  scrollDiv.style.height = '100px';
  scrollDiv.style.overflow = 'scroll';
  scrollDiv.style.position = 'absolute';
  scrollDiv.style.top = '-9999px';

  document.body.appendChild(scrollDiv);
  const scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
  document.body.removeChild(scrollDiv);

  return scrollbarWidth;
}

We show the scrollbar for a div, and the trick is, offsetWidth includes the bar, but clientWidth doesn't.

Then we can get the width without scrollbar:

const widthWithoutScrollbar = window.innerWidth - getScrollbarWidth()

After we use this width for body and the fixed header, everything is as still as night:

Enjoy! And try notenote.cc