2つのスクロールバーをjQueryで同期させる方法
こんにちは、「インターライフメディア ブログ」編集部です。Webサイトを制作していると、「こちらのスクロール領域を動かしたら、もう一方の領域も一緒にスクロールしてほしい」というUI要件が出てくることがあります。
例えば、縦長のテーブルでヘッダーを固定しつつ、横スクロールはヘッダーとボディで連動させたい場合や、2つのリストを並べて比較しやすくしたい場合などです。
今回は、このような「スクロールの同期」をjQueryを使って簡単に実装する一例をご紹介します。
デモ
まずは実際の動作をご覧ください。片方のエリアをスクロールすると、もう一方も追従してスクロールするのが分かります。
HTMLの解説
まず、同期させたいスクロール領域をHTMLで用意します。重要なのは、JavaScriptから操作対象として識別できるよう、特定のidやclassを割り振っておくことです。
今回のデモでは、id="js-scroll_drag_area" と id="js-scroll_drag_area-2" という2つのIDをそれぞれ<div>タグに設定しています。
<!-- 同期させたいエリア1 -->
<div class="scroll_area" id="js-scroll_drag_area">
<div class="scrollinner">
<ul><li>1</li><li>2</li><li>3</li><!-- ...中略... --><li>31</li></ul>
</div>
</div>
<!-- 同期させたいエリア2 -->
<div class="scroll_area scroll_area-2" id="js-scroll_drag_area-2">
<div class="scrollinner">
<ul><li>1</li><li>2</li><li>3</li><!-- ...中略... --><li>31</li></ul>
</div>
</div>
CSS (SCSS) の解説
CSSのポイントは、スクロールバーを発生させることです。.scroll_area に対して overflow: auto;(または overflow: scroll;)を指定し、width と height で領域のサイズを固定します。
領域内のコンテンツ(.scrollinner)がそのサイズを超えることで、スクロールバーが出現します。jsfiddleのデモではSCSSで記述されていますが、基本的な考え方はCSSと同じです。
/* デモ内のCSS(SCSS)の抜粋 */
.scroll_area {
width: 100%;
height: 200px;
overflow: auto; /* スクロールバーを出すための鍵 */
border: 1px solid #ccc;
.scrollinner {
width: 1000px; /* 横スクロールを発生させるため */
ul {
display: flex;
li {
flex: 0 0 100px;
/* ... */
}
}
}
}
JavaScript (jQuery) の解説
ここがスクロール同期の核となる部分です。ロジックは非常にシンプルです。
- 片方のエリアで「スクロールイベント」が発生するのを監視します。
- イベントが発生したら、そのエリアの現在のスクロール量(縦・横)を取得します。
- 取得したスクロール量を、もう一方のエリアに即座に設定します。
以下のコードを見てみましょう。
/* スクロール同期
-------------------------------------------------- */
function scroll_synch($scrollArea, $target){
// $scrollArea で指定された要素がスクロールされたら処理を実行
$($scrollArea).on('scroll', function(){
// $(this) はスクロールされた要素($scrollArea)を指す
var amountX = $(this).scrollLeft(); // 横方向のスクロール量を取得
var amountY = $(this).scrollTop(); // 縦方向のスクロール量を取得
// 取得したスクロール量を $target(もう一方の要素)に設定
$($target).scrollLeft(amountX);
$($target).scrollTop(amountY);
});
}
// Aが動いたらBを動かす
scroll_synch('#js-scroll_drag_area', '#js-scroll_drag_area-2');
// Bが動いたらAを動かす
scroll_synch('#js-scroll_drag_area-2', '#js-scroll_drag_area');
ポイントは、scroll_synch関数を2回呼び出している点です。
1回目の呼び出し(scroll_synch('#js-scroll_drag_area', ...))で、「エリア1がスクロールされたら、エリア2を動かす」設定をします。
2回目の呼び出し(scroll_synch('#js-scroll_drag_area-2', ...))で、「エリア2がスクロールされたら、エリア1を動かす」設定をします。
これにより、どちらのエリアを操作しても、もう一方が追従する「双方向のスクロール同期」が実現できます。
まとめ
jQueryを使うと、.on('scroll') イベントでスクロール量を監視し、.scrollLeft() と .scrollTop() で値を取得・設定するだけで、簡単にスクロール同期が実装できます。UIの改善やデータ比較の見せ方などで役立つテクニックですので、ぜひ活用してみてください。
よくある質問(FAQ)
Q1. jQueryを使わずに、素のJavaScript (Vanilla JS) でも実装できますか?
A1. はい、実装可能です。jQueryの .on('scroll', ...) は addEventListener('scroll', ...) に、.scrollLeft() / .scrollTop() は、そのまま element.scrollLeft / element.scrollTop プロパティの読み書きに置き換えることで実現できます。
Q2. 縦スクロール(または横スクロール)だけを同期させることはできますか?
A2. 可能です。上記のJavaScriptコード内で、不要な方の処理をコメントアウトまたは削除します。例えば、横スクロールだけを同期させたい場合は、.scrollTop() に関連する2行を削除(またはコメントアウト)してください。
/* 横スクロールのみ同期する場合 */
function scroll_synch($scrollArea, $target){
$($scrollArea).on('scroll', function(){
var amountX = $(this).scrollLeft();
// var amountY = $(this).scrollTop(); // 縦スクロールの取得を無効化
$($target).scrollLeft(amountX);
// $($target).scrollTop(amountY); // 縦スクロールの設定を無効化
});
}
Q3. コードを試しても動かない場合、どんな原因が考えられますか?
A3. 初心者の方がつまずきやすい点として、以下の2点を確認してみてください。
1. jQueryが正しく読み込めていない: <script>タグでjQuery本体を、作成したスクリプトより「前」で読み込んでいるか確認してください。
2. id名やclass名が一致していない: HTML側で指定したid(例: #js-scroll_drag_area)と、JavaScript側で指定したセレクタが、大文字小文字や綴りを含めて完全に一致しているか確認してください。