横に長いテーブルをスマートフォンで表示するとき、横スクロール自体はCSSのoverflow-x: autoで簡単に実装できます。
ただ、ブラウザ標準のスクロールバーは環境によって見た目が異なり、デザインに合わせづらいことがあります。また、スクロールバーが細かったり、常時表示されなかったりするため、横にスクロールできることがユーザーに伝わりにくい場合もあります。
そこで、横に長いコンテンツへドラッグ可能なカスタムスクロールバーを追加できるVanilla JSライブラリ、@neruco/horizontal-scrollを作成しました。
https://www.npmjs.com/package/@neruco/horizontal-scroll
npm install @neruco/horizontal-scroll
HorizontalScrollは、テーブルだけでなく、カード一覧、画像一覧、コードブロックなど、横方向にはみ出すさまざまなコンテンツに利用できます。外部ライブラリに依存せず、同じページ内への複数設置にも対応しています。
サンプル
See the Pen HorizontalScroll by あお@neruco (@coder_ao) on CodePen.
HorizontalScrollの特徴
主な特徴は次のとおりです。
- Vanilla JavaScriptで実装
- 外部ライブラリへの依存なし
- ページ内への複数設置に対応
- スクロールバーのつまみをドラッグ可能
- スクロールバートラックのクリックに対応
- スマートフォンではコンテンツを直接スワイプ可能
- テーブル以外の横長コンテンツにも使用可能
- ESM、CommonJS、IIFE形式に対応
- TypeScriptの型定義を同梱
ResizeObserverによるサイズ変更の自動検知update()とdestroy()を用意
JavaScript用のフッククラスには、.js-horizontalScrollのようなjs-接頭辞とキャメルケースを採用しています。
基本的なHTML
基本構造は次のとおりです。
<div class="js-horizontalScroll">
<div class="js-horizontalScroll__viewport">
<div>
横に長いコンテンツ
</div>
</div>
<div
class="js-horizontalScroll__scrollbar"
aria-hidden="true"
>
<div class="js-horizontalScroll__thumb"></div>
</div>
</div>
それぞれの要素には、次の役割があります。
.js-horizontalScroll:コンポーネント全体.js-horizontalScroll__viewport:実際に横スクロールする領域.js-horizontalScroll__scrollbar:カスタムスクロールバーのトラック.js-horizontalScroll__thumb:ドラッグするつまみ
横に長くなるコンテンツは、.js-horizontalScroll__viewportの中に配置します。
npmからインストールする
npmを利用しているプロジェクトでは、次のコマンドでインストールできます。
npm install @neruco/horizontal-scroll
JavaScriptとCSSを読み込み、インスタンスを作成します。
import HorizontalScroll from "@neruco/horizontal-scroll";
import "@neruco/horizontal-scroll/style.css";
const horizontalScroll = new HorizontalScroll(
".js-horizontalScroll"
);
ページ内に複数の.js-horizontalScrollがある場合も、一度の初期化ですべての要素へ適用されます。それぞれのスクロール領域は独立して動作します。
テーブルに使用する
横に長い比較表などには、次のように使用できます。
<div class="js-horizontalScroll">
<div class="js-horizontalScroll__viewport">
<table class="comparisonTable">
<thead>
<tr>
<th scope="col">項目</th>
<th scope="col">商品A</th>
<th scope="col">商品B</th>
<th scope="col">商品C</th>
<th scope="col">商品D</th>
</tr>
</thead>
<tbody>
<tr>
<th scope="row">価格</th>
<td>¥1,200</td>
<td>¥1,500</td>
<td>¥980</td>
<td>¥2,100</td>
</tr>
<tr>
<th scope="row">重量</th>
<td>120g</td>
<td>150g</td>
<td>100g</td>
<td>180g</td>
</tr>
<tr>
<th scope="row">保証期間</th>
<td>1年</td>
<td>2年</td>
<td>6か月</td>
<td>3年</td>
</tr>
</tbody>
</table>
</div>
<div
class="js-horizontalScroll__scrollbar"
aria-hidden="true"
>
<div class="js-horizontalScroll__thumb"></div>
</div>
</div>
テーブル自体には、横スクロールが発生する幅を指定します。
.comparisonTable {
width: 900px;
border-collapse: collapse;
}
.comparisonTable th,
.comparisonTable td {
padding: 12px;
border: 1px solid #ccc;
white-space: nowrap;
}
コンテンツの幅が表示領域より小さく、横スクロールが不要な場合は、カスタムスクロールバーも非表示になります。
カード一覧に使用する
HorizontalScrollはテーブル専用ではありません。
横並びのカード一覧にも利用できます。
<div class="js-horizontalScroll">
<div class="js-horizontalScroll__viewport">
<div class="cardList">
<article class="cardList__item">
カード1
</article>
<article class="cardList__item">
カード2
</article>
<article class="cardList__item">
カード3
</article>
<article class="cardList__item">
カード4
</article>
</div>
</div>
<div
class="js-horizontalScroll__scrollbar"
aria-hidden="true"
>
<div class="js-horizontalScroll__thumb"></div>
</div>
</div>
.cardList {
display: flex;
gap: 16px;
width: max-content;
}
.cardList__item {
width: 260px;
flex-shrink: 0;
padding: 24px;
border: 1px solid #ccc;
}
このほかにも、次のようなコンテンツに使用できます。
- 画像ギャラリー
- 横並びのナビゲーション
- 料金プランの比較表
- スケジュール表
- コードブロック
- 横長の図やフローチャート
scriptタグで読み込む
IIFE版も用意しているため、npmを使用しない静的HTMLやWordPressテーマでも利用できます。IIFE版では、HorizontalScrollがブラウザのグローバル変数として公開されます。
CSSとIIFE版のJavaScriptを読み込みます。
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@neruco/horizontal-scroll@1.0.2/dist/horizontal-scroll.css"
>
<script src="https://cdn.jsdelivr.net/npm/@neruco/horizontal-scroll@1.0.2/dist/horizontal-scroll.iife.js"></script>
読み込み後に初期化します。
<script>
const horizontalScroll = new HorizontalScroll(
".js-horizontalScroll"
);
</script>
WordPressテーマで使用する場合は、ビルド後のファイルをテーマ内へ配置し、wp_enqueue_style()とwp_enqueue_script()で読み込めます。
<?php
function theme_enqueue_horizontal_scroll() {
wp_enqueue_style(
'horizontal-scroll',
get_template_directory_uri() . '/assets/css/horizontal-scroll.css',
array(),
'1.0.2'
);
wp_enqueue_script(
'horizontal-scroll',
get_template_directory_uri() . '/assets/js/horizontal-scroll.iife.js',
array(),
'1.0.2',
true
);
}
add_action( 'wp_enqueue_scripts', 'theme_enqueue_horizontal_scroll' );
初期化用のJavaScriptは、IIFE版より後に実行します。
document.addEventListener("DOMContentLoaded", () => {
const horizontalScroll = new HorizontalScroll(
".js-horizontalScroll"
);
});
オプションを指定する
第2引数でオプションを指定できます。
const horizontalScroll = new HorizontalScroll(
".js-horizontalScroll",
{
minThumbWidth: 48,
smoothTrackClick: false,
}
);
minThumbWidth
つまみの最小幅をピクセル単位で指定します。
new HorizontalScroll(".js-horizontalScroll", {
minThumbWidth: 48,
});
初期値は40です。
コンテンツが非常に横長い場合でも、つまみが小さくなりすぎるのを防げます。
smoothTrackClick
スクロールバーのトラックをクリックしたとき、スムーススクロールさせるか指定します。
new HorizontalScroll(".js-horizontalScroll", {
smoothTrackClick: false,
});
初期値はtrueです。
セレクターを変更する
プロジェクト独自のクラス名にも変更できます。
new HorizontalScroll(".js-cardScroll", {
viewportSelector: ".js-cardScroll__viewport",
scrollbarSelector: ".js-cardScroll__scrollbar",
thumbSelector: ".js-cardScroll__thumb",
});
使用できるオプションには、各要素のセレクター、状態クラス、つまみの最小幅、トラッククリック時の挙動があります。
動的に内容を変更した場合
横スクロール領域の内容をJavaScriptで変更した場合は、update()でスクロールバーを再計算できます。
horizontalScroll.update();
通常のサイズ変更はResizeObserverで監視されますが、DOMを書き換えた直後など、任意のタイミングで再計算したい場合に利用できます。
インスタンスを破棄する
登録されたイベントや監視を解除する場合は、destroy()を実行します。
horizontalScroll.destroy();
destroy()を実行すると、イベントリスナー、ResizeObserver、状態クラス、つまみに設定されたインラインスタイルなどが解除されます。
CSSをカスタマイズする
同梱CSSをそのまま利用できますが、スクロールバーの色や太さはプロジェクトに合わせて変更できます。
.js-horizontalScroll__scrollbar {
height: 10px;
margin-top: 16px;
background-color: #e5e5e5;
border-radius: 9999px;
}
.js-horizontalScroll__thumb {
background-color: #666;
border-radius: inherit;
}
JavaScript側では、スクロールバーとつまみの幅・位置を制御します。
色、余白、角丸、太さなどの見た目はCSS側で自由に調整できます。
まとめ
@neruco/horizontal-scrollは、横に長いコンテンツへカスタムスクロールバーを追加するための軽量なVanilla JSライブラリです。
テーブル専用ではないため、比較表、カード一覧、画像一覧など、さまざまなコンテンツに利用できます。
npmを使うプロジェクトではES Modules版、WordPressや静的HTMLではIIFE版を利用できます。
npm install @neruco/horizontal-scroll
今後も実案件で使用しながら、使いやすい形へ改善していく予定です。
- PR
