OSやブラウザのスクロールバーによって、レイアウトが崩れたり、意図しない余白が生じたりするなど、コンテンツの表示が影響を受けることはよくあります。例えば、テキストの改行位置が変わり、デザインとのずれが生じるなどです。
通常は特に気にする必要はありませんが、特定のコンテンツ内でのみスクロールを制御する必要があったため、スクロールバーの影響を受けずにコンテンツを表示する方法を探したところ、以下の方法を見つけました。
See the Pen Calculate Scrollbar Size by H. Maniwa (@HManiwa) on CodePen.
※ なぜかCodepenが表示されません😣
CSS
scrollbar-gutter
プロパティでスクロールバーの表示領域を確保し、CSSカスタム変数で設定したスクロールバーの幅をコンテンツの余白から差し引きます。
scrollbar-gutter - MDN
:root {
--box-padding: 24px;
--scrollbar-size: 0px;
}
.box {
inline-size: 400px;
block-size: 400px;
overflow: hidden;
}
.inner {
padding: var(--box-padding);
block-size: 100%;
overflow: auto;
}
#box-2 > .inner {
padding-inline-end: calc( var(--box-padding) - var(--scrollbar-size) );
scrollbar-gutter: stable;
}
JavaScript
getScrollbarSize()
関数は、スクロールバーのサイズを取得し、取得した値をCSSカスタムプロパティ--scrollbar-size
にsetProperty()
メソッドを使って設定します。
この関数は、一時的なdiv
要素を生成してbody
に追加し、その要素のオフセット幅/高さとクライアント幅/高さの差分を調べることで、スクロールバーのサイズを算出しています。
要素にスクロールバーが表示されている場合、オフセット幅/高さにはスクロールバーの幅/高さが含まれますが、クライアント幅/高さには含まれません。この差を利用することで、スクロールバーのサイズを算出できます。
この差分がスクロールバーのサイズとなり、その値が返されます。1
function getScrollbarSize() {
const div = document.createElement("div");
div.style.overflow = "scroll";
div.style.width = "100px";
div.style.height = "100px";
div.style.position = "absolute";
div.style.visibility = "hidden";
document.body.appendChild(div);
const scrollbarWidth = div.offsetWidth - div.clientWidth;
const scrollbarHeight = div.offsetHeight - div.clientHeight;
document.body.removeChild(div);
return { width: scrollbarWidth, height: scrollbarHeight };
}
const scrollbarSize = getScrollbarSize();
document.documentElement.style.setProperty(
"--scrollbar-size",
`${scrollbarSize.width}px`
);
-
ここでは縦スクロールバーのサイズのみを取得しているため、
scrollbarSize
オブジェクトのwidth
プロパティを使用しています。縦横両方のスクロールバーの値を設定する場合は、コードを適宜修正してください。 ↩