Webサイトのデザインに合わせて、スクロールバーの見た目も細かく調整したい。そう考えるWeb制作者の方は多いのではないでしょうか。
CSSの::-webkit-scrollbarなどを使えばある程度のカスタマイズは可能ですが、対応ブラウザが限られる(主にWebKit系)という課題があります。かといって、多機能なプラグインを導入するほどでもない…というケースもあるでしょう。
今回は、プラグインを使わずにJavaScript (jQuery) とHTML/CSSを組み合わせて、ブラウザに依存しない「自作スクロールバー(擬似的スクロールバー)」を実装する一例を紹介します。
HTMLの解説
まず、基本的な構造を組みます。ポイントは以下の3点です。
- 実際にスクロールさせたい領域(
.scroll_area) - それを囲う親要素(
.scroll_area_wrap) - 擬似スクロールバーとして表示する要素(
.scrollbar_custom)
.scroll_areaにはoverflow: scroll;(または auto)を設定し、ブラウザ標準のスクロールバー(後で非表示にします)でスクロールできる状態にします。擬似スクロールバー(.scrollbar_custom)は、JavaScriptで操作するためにjs-scrollbarYやjs-scrollbar1といったクラス名を付けています。
<div class="scroll_area_wrap">
<!-- 実際にスクロールするエリア -->
<div class="scroll_area" id="js-scroll_drag_area">
<div class="scrollinner">
ここのエリアをスクロールする。
<ul>
<li>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</li>
<li>テキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキストテキスト</li>
</ul>
</div>
</div>
<!-- 擬似スクロールバー(縦) -->
<div class="js-scrollbarY scrollbar_custom scrollbar_custom_y"><span></span></div>
<!-- 擬似スクロールバー(横) -->
<div class="js-scrollbar1 scrollbar_custom scrollbar_custom_btm"><span></span></div>
</div>
SCSS (CSS) の解説
次にスタイルを当てていきます。ここではSCSSを使用していますが、基本的な考え方はCSSと同じです。
重要なのは、親要素の.scroll_area_wrapにposition: relative;を指定し、その子要素である.scroll_areaと.scrollbar_customをposition: absolute;で重ねて配置することです。
.scroll_areaはwidth: 100%; height: 100%;で親要素いっぱいに広げ、overflow: scroll;で中身をスクロール可能にします。(この時点ではブラウザ標準のスクロールバーが見えていますが、最終的にはJavaScriptで制御する擬似スクロールバーが上に重なります。)
擬似スクロールバー(.scrollbar_custom)内のspanが、実際に動く「つまみ」の部分です。このspanの幅(width)や高さ(height)は、後述するJavaScriptの計算と密接に関係します。
.scroll_area_wrap {
margin: 2em;
display: block;
width: 300px;
height: 300px;
position: relative;
background: yellow;
color: brown;
/* 本番環境では .scroll_area の標準スクロールバーを非表示にする設定を追加推奨 */
/* 例:
.scroll_area {
-ms-overflow-style: none; // IE
scrollbar-width: none; // Firefox
&::-webkit-scrollbar { // Chrome, Safari
display: none;
}
}
*/
}
.scroll_area {
position: absolute;
width: 100%;
height: 100%;
overflow: scroll; /* スクロール自体はブラウザの機能に任せる */
}
.scrollinner {
padding: 2em;
width: 1200px; /* 表示領域よりわざと大きく設定 */
height: 1200px; /* 表示領域よりわざと大きく設定 */
box-sizing: border-box;
}
//擬似スクロールバー
.scrollbar_custom {
padding: 1px;
position: absolute;
top: 0;
left: 0;
z-index: 700;
width: 100%;
height: 17px;
pointer-events: none; /* バー自体がクリックイベントを奪わないようにする */
background: #fff;
box-shadow: inset 0 0 10px rgba(#000, 0.3);
span {
border-radius: 10px;
display: block;
position: relative;
width: 33%; /* JSの bar_percent と連動 */
height: 100%;
pointer-events: none;
background: blue;
//opacity: .8;
$bar_color: #458ec5; // #2d6691;
background: linear-gradient(
to bottom,
rgba($bar_color, 0.5) 0%,
rgba($bar_color, 0.6) 26%,
rgba($bar_color, 0.7) 51%,
rgba($bar_color, 0.8) 62%,
rgba($bar_color, 0.9) 75%,
rgba($bar_color, 0.8) 88%,
rgba($bar_color, 1) 100%
); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
}
&.scrollbar_custom_btm {
top: auto;
bottom: 0;
}
&.scrollbar_custom_y {
left: auto;
right: 0;
width: 17px;
height: 100%;
span {
width: 100%;
height: 33%; /* JSの bar_percent と連動 */
}
}
}
JavaScript (jQuery) の解説
最後に、実際のスクロールイベント(.on('scroll', ...))を監視し、そのスクロール量に合わせて擬似スクロールバーの「つまみ」(span)を動かす処理を記述します。
.scrollLeft()(横スクロール量)または.scrollTop()(縦スクロール量)を取得し、それを「最大スクロール可能量」で割ることで、現在のスクロール位置が全体の何%かを算出します。
その割合(%)を使って、擬似スクロールバーのspanのleftまたはtopの位置をCSSで動かしています。
【重要】
以下のサンプルコードでは、計算を簡略化するため「最大スクロール量(scroll_amount = 915)」と「バーの長さ(bar_percent = 33)」を**固定値(ハードコーディング)**にしています。
実際の制作で使う場合は、これらの値を固定にするのではなく、
- 最大スクロール量:
$(this)[0].scrollWidth - $(this).innerWidth()(横軸の場合) - バーの比率:
$(this).innerWidth() / $(this)[0].scrollWidth * 100(横軸の場合)
のように、jQueryやJavaScriptを使って**動的に取得・計算する**必要があります。このサンプルは、あくまで「スクロール量に連動させてCSSを動かす」という仕組みを理解するためのものとしてご覧ください。
/* スクロール同期 X軸
-------------------------------------------------- */
function scroll_synch_X($scrollArea, $target) {
$($scrollArea).on('scroll', function () {
//console.log('X:'+$(this).scrollLeft()); //デバッグ用:限界のスクロール量を測定
// ↓↓【注意】本来は動的に計算すべき値 ↓↓
var scroll_amount = 915; // サンプル上の最大スクロール量 (scrollWidth - innerWidth)
var bar_percent = 33; // サンプル上のバーの長さ (%) (innerWidth / scrollWidth * 100)
// ↑↑【注意】ここまで ↑↑
// (現在のスクロール量 / 最大スクロール量) * (バーが動ける範囲の割合)
var amountX =
($(this).scrollLeft() / scroll_amount) * (100 - bar_percent);
// 100からバーの長さ(%)を引くことで、バーが移動できる最大値(例: 100% - 33% = 67%)を算出
$($target).css('left', amountX + '%');
});
}
/* スクロール同期 Y軸
-------------------------------------------------- */
function scroll_synch_Y($scrollArea, $target) {
$($scrollArea).on('scroll', function () {
//console.log('Y:'+$(this).scrollTop()); //デバッグ用
// ↓↓【注意】本来は動的に計算すべき値 ↓↓
var scroll_amount = 915; // サンプル上の最大スクロール量 (scrollHeight - innerHeight)
var bar_percent = 33; // サンプル上のバーの長さ (%) (innerHeight / scrollHeight * 100)
// ↑↑【注意】ここまで ↑↑
var amountY =
($(this).scrollTop() / scroll_amount) * (100 - bar_percent);
$($target).css('top', amountY + '%');
});
}
// 実行
scroll_synch_X('#js-scroll_drag_area', '.js-scrollbar1 span');
scroll_synch_Y('#js-scroll_drag_area', '.js-scrollbarY span');
まとめ
今回は、JavaScript (jQuery) を使ってスクロールバーを自作する基本的な仕組みを紹介しました。この方法を使えば、ブラウザ標準のスクロールバーを非表示にし、完全にオリジナルのデザインを適用できます。
サンプルコードでは数値を固定化しているため、実用化するにはコンテンツ量に応じた動的な計算処理が必要になりますが、基本的な考え方は同じです。「スクロールイベントを監視し、その割合に応じて別の要素のCSSを操作する」というテクニックは、スクロールバー以外にも応用が効くので、ぜひ覚えてみてください。
よくある質問(FAQ)
Q1. JavaScript内の scroll_amount や bar_percent の数値は、そのまま使えますか?
A1. いいえ、そのままでは使えません。これらはサンプルコード内の特定の幅・高さ(300pxの領域に1200pxのコンテンツ)に依存した固定値です。実際のWebサイトで利用する場合は、これらの値をJavaScriptで動的に計算する必要があります。
例えば、横軸の場合、最大スクロール量は「コンテンツ全体の幅(scrollWidth) – 表示領域の幅(innerWidth)」、バーの比率は「表示領域の幅(innerWidth) / コンテンツ全体の幅(scrollWidth)」といった計算式で求められます。
Q2. なぜCSSの ::-webkit-scrollbar を使わないのですか?
A2. ::-webkit-scrollbar は非常に手軽なカスタマイズ方法ですが、ChromeやSafariといったWebKit系ブラウザでしか動作しません。Firefoxやその他のブラウザには適用されないため、ブラウザ間でデザインを統一したい場合には不向きです。本記事の方法は、ブラウザ標準のバーを非表示にしてDOM要素で擬似的にバーを作成するため、ブラウザ間の差異を気にする必要がありません。
Q3. もっと簡単に実装する方法はありますか?
A3. はい、あります。スクロールバーのカスタマイズ専用のJavaScriptライブラリ(プラグイン)を使えば、より簡単に高機能なスクロールバーを実装できます。代表的なものに「Perfect Scrollbar」や「SimpleBar」などがあります。本記事の方法は、あえてライブラリに頼らず、仕組みを理解しながら自作したい方向けのテクニックとなります。
