【PR】を含みます。

フロントエンド

【JavaScript】完全自作スクロールバーの作り方|CSS非依存でデザイン自由自在

JavaScript 完全自作スクロールバーの作り方|CSS非依存でデザイン自由自在

通常、スクロールバーのデザインはCSSでしか変更できませんが、JavaScriptを使えば「完全自作のスクロールバー」を実現できます。

本記事では、標準スクロールバーを非表示にしてホバー時に表示・ドラッグで操作できるカスタムスクロールバースマホでも動作するカスタムスクロールバーをゼロから実装する方法を解説します。

スクロールバーをCSSでカスタマイズする方法は以下の記事で紹介しています。

あわせて読む
CSS スクロールバーのデザインをカスタマイズする方法

【CSS】スクロールバーのデザインをカスタマイズする方法

もくじスクロールバーをカスタマイズできるブラウザ基本的なカスタマイズ方法(Chrome / Edge / Safari)Firefoxでのカスタマイズ方法クロスブラウザ対応の書き方ダークモード+ホバー ...

JavaScriptでスクロールバーを自作するメリット

通常のスクロールバーはブラウザやOSによってデザインが異なり、サイト全体の統一感を損なうことがあります。

JavaScriptでスクロールバーを自作すると、以下のようなメリットがあります。

  • サイトデザインに合わせて完全カスタマイズ可能
  • ホバー表示やアニメーションにも対応
  • ドラッグ・タッチ操作など、より自然な操作感を再現できる

完成イメージ

  • 標準スクロールバーは非表示
  • マウスホバーでフェードイン
  • つまみ(thumb)をドラッグで操作可能
  • スマホでも指で動かせる

【サンプル】自作スクロールバー

自作スクロールバーのデモです。

このように、スクロールコンテナの中に多くのテキストを入れると...

下に進むとスクロールバーが機能します。

ホバーするとスクロールバーが表示されます。

さらに、つまみをドラッグして操作も可能です。

スマホでも指で動かせます。

【実装コード】自作スクロールバーを実装する

HTMLの基本構造

Copyをクリックするとコピーできます。

HTML
Copy
<div class="scroll-container">
  <div class="scroll-content">
    <p>自作スクロールバーのデモです。</p>
    <p>このように、スクロールコンテナの中に多くのテキストを入れると...</p>
    <p>下に進むとスクロールバーが機能します。</p>
    <p>ホバーするとスクロールバーが表示されます。</p>
    <p>さらに、つまみをドラッグして操作も可能です。</p>
    <p>スマホでも指で動かせます。</p>
  </div>
  <div class="custom-scrollbar">
    <div class="custom-thumb"></div>
  </div>
</div>

CSSでデザインを整える

Copyをクリックするとコピーできます。

CSS
Copy
.scroll-container {
  position: relative;
  width: 100%;
  max-width: 300px;
  height: 200px;
  padding: 10px;
  overflow: hidden; /* 標準スクロールバーを非表示 */
  border: 1px solid #ccc;
  border-radius: 6px;
}
.scroll-content {
  height: 100%;
  overflow-y: scroll;
  padding-right: 20px; /* カスタムバー分の余白 */
  scrollbar-width: none; /* Firefoxで非表示 */
}
.scroll-content::-webkit-scrollbar {
  display: none; /* Chrome/Safariで非表示 */
}
.custom-scrollbar {
  position: absolute;
  top: 0;
  right: 2px;
  width: 6px;
  height: 100%;
  background: rgba(0, 0, 0, 0.05);
  opacity: 0;
  transition: opacity 0.3s;
  pointer-events: none;
}
/* ホバーでフェードイン */
.scroll-container:hover .custom-scrollbar {
  opacity: 1;
  pointer-events: auto;
}
.custom-thumb {
  position: absolute;
  top: 0;
  width: 100%;
  height: 40px;
  background: #666;
  border-radius: 3px;
  transition: background 0.2s;
  cursor: grab;
}
.custom-thumb:hover {
  background: #444;
}
/* スマホでは常時表示(hoverが使えないため) */
@media (hover: none) and (pointer: coarse) {
  .custom-scrollbar {
    opacity: 1;
    pointer-events: auto;
  }
}

JavaScriptでスクロールを制御(PC版)

PCで動作させるための基本コードは以下の通りです。

Copyをクリックするとコピーできます。

JavaScript
Copy
document.addEventListener('DOMContentLoaded', function() {
  const container = document.querySelector('.scroll-container');
  const content = container.querySelector('.scroll-content');
  const scrollbar = container.querySelector('.custom-scrollbar');
  const thumb = scrollbar.querySelector('.custom-thumb');
  function updateThumb() {
    const ratio = container.clientHeight / content.scrollHeight;
    const thumbHeight = Math.max(ratio * container.clientHeight, 30);
    thumb.style.height = thumbHeight + 'px';
    const scrollTopRatio = content.scrollTop / (content.scrollHeight - container.clientHeight);
    thumb.style.top = scrollTopRatio * (container.clientHeight - thumbHeight) + 'px';
  }
  content.addEventListener('scroll', updateThumb);
  window.addEventListener('resize', updateThumb);
  updateThumb();
});

JavaScriptでスクロールを制御(スマホ対応)

スマホではmousedownmousemoveが使えないため、touchstart,touchmove,touchendを追加します。

Copyをクリックするとコピーできます。

JavaScript
Copy
document.addEventListener('DOMContentLoaded', function() {
  const container = document.querySelector('.scroll-container');
  const content = container.querySelector('.scroll-content');
  const scrollbar = container.querySelector('.custom-scrollbar');
  const thumb = scrollbar.querySelector('.custom-thumb');
  function updateThumb() {
    const ratio = container.clientHeight / content.scrollHeight;
    const thumbHeight = Math.max(ratio * container.clientHeight, 30);
    thumb.style.height = thumbHeight + 'px';
    const scrollTopRatio = content.scrollTop / (content.scrollHeight - container.clientHeight);
    thumb.style.top = scrollTopRatio * (container.clientHeight - thumbHeight) + 'px';
  }
  content.addEventListener('scroll', updateThumb);
  window.addEventListener('resize', updateThumb);
  updateThumb();
  let isDragging = false;
  let startY, startScrollTop;
  function startDrag(clientY) {
    isDragging = true;
    startY = clientY;
    startScrollTop = content.scrollTop;
    thumb.style.cursor = 'grabbing';
    document.body.style.userSelect = 'none';
  }
  function moveDrag(clientY) {
    if (!isDragging) return;
    const deltaY = clientY - startY;
    const scrollRatio = (content.scrollHeight - container.clientHeight) / (container.clientHeight - thumb.clientHeight);
    content.scrollTop = startScrollTop + deltaY * scrollRatio;
  }
  function endDrag() {
    isDragging = false;
    thumb.style.cursor = 'grab';
    document.body.style.userSelect = '';
  }
  // --- マウス操作 ---
  thumb.addEventListener('mousedown', e => startDrag(e.clientY));
  document.addEventListener('mousemove', e => moveDrag(e.clientY));
  document.addEventListener('mouseup', endDrag);
  // --- タッチ操作(スマホ対応) ---
  thumb.addEventListener('touchstart', e => startDrag(e.touches[0].clientY));
  document.addEventListener('touchmove', e => moveDrag(e.touches[0].clientY));
  document.addEventListener('touchend', endDrag);
});

スマホ対応のポイント

課題対策
hoverが使えないスマホでは.custom-scrollbarを常時表示
マウスイベントが無効touchstart,touchmove,touchendを追加
スクロール追従scrollイベントでthumb位置を更新
スクロールの遅延スクロール領域をネイティブ処理に任せる

仕組みの解説(ドラッグ操作とは?)

「ドラッグ操作」とは、つまみ(thumb)をマウスや指で掴んで動かし、それに応じてスクロールを制御する仕組みのことです。

イベント内容
mousedown/touchstartつまみを掴んでドラッグ開始
mousemove/touchmoveマウスまたは指の動きに合わせてスクロール量を更新
mouseup/touchend離してドラッグ終了

これにより、標準スクロールバーと同じ操作感を再現できます。

まとめ

JavaScriptを使えば、CSSでは制御できない完全自作のスクロールバーを実現できます。

本記事のポイント

  • 標準スクロールバーを非表示にしてデザイン統一
  • ホバー表示で視認性UP
  • PC・スマホどちらでもドラッグ操作に対応
  • CSS・JSのみで完結、ライブラリ不要

応用例

  • 横方向スクロールにも対応可能
  • スクロール位置に応じて色を変化
  • スクロールアニメーションとの組み合わせ

今回のコードをベースに、あなたのWebデザインに合わせて自由に拡張してみてください。

-フロントエンド
-