スクロールバーの幅を取得する JavaScript

Web ページに表示されるスクロールバーの幅は、OS やブラウザによって幅が異なる。大体 15 〜 18px 程度だが、数ピクセルのズレも許せない場合があるだろう。

そんな時は以下のような JavaScript コードで、そのブラウザにおけるスクロールバーの幅を取得できる。

/** スクロールバーの幅 (ピクセル単位) を取得する */
function getScrollbarWidth() {
  // スクロールバーの幅を取得するための要素を生成する   
  const scrollbarElem = document.createElement('div');
  // 要素の幅をビューポート幅 (スクロールバーを含む幅) で指定する・要素が画面に表示されないよう処理しておく
  scrollbarElem.setAttribute('style', 'visibility: hidden; position: absolute; top: 0; left: 0; width: 100vw;');
  // 画面表示上のピクセル数を拾うために一旦 body 要素に挿入する
  document.body.appendChild(scrollbarElem);
  // ビューポート幅を取得しておく ('0px' と単位付きで取得されるので parseInt() で単位を除去する)
  const vw = parseInt(window.getComputedStyle(scrollbarElem).width);
  // 要素の幅をパーセント幅 (スクロールバーを除く幅) で指定する
  scrollbarElem.style.width = '100%';
  // パーセント幅を取得する
  const pc = parseInt(window.getComputedStyle(scrollbarElem).width);
  // 要素を削除する
  document.body.removeChild(scrollbarElem);
  // ビューポート幅とパーセント幅の差分がスクロールバーの幅 (px) となる
  const scrollbarWidth = vw - pc;
  // スクロールバーの幅を返却する
  return scrollbarWidth;
}

仕組みは簡単。幅 100vw を指定した要素と、幅 100% を指定した要素の実際のサイズを window.getComputedStyle() で取得し、そのピクセル数の差分を取得するだけ。

100vw (ViewPort Width) がスクロールバーを含まない幅100% (パーセント) がスクロールバーを含む幅になるので、自動的にスクロールバーの幅が算出できるというワケ。

既存の要素に影響を与えないよう、適当な要素を visibility: hidden で非表示にしながら body に追加し、そのラッパー要素の中に入れた要素の幅を変更することで値を取得している。


ngx-bootstrap のモーダルで padding-right を操作するおかしな処理があったので調べたところから着想を得た。