SimpleBar.jsでスクロールバーを美しく!【実装レシピ&サンプル付き】
SimpleBar.jsとは?
- ネイティブスクロールを維持しつつ、カスタム見た目のスクロールバーを実現する軽量ライブラリ
- スクロール機能自体はブラウザに任せるため、パフォーマンスとアクセシビリティに優れます
- 既存要素に
data-simplebarを付けるだけでも動作
導入方法
1) CDNで手早くお試し
<!-- head内 -->
<link rel="stylesheet" href="https://unpkg.com/simplebar@latest/dist/simplebar.min.css">
<script defer src="https://unpkg.com/simplebar@latest/dist/simplebar.min.js"></script>
2) npmでプロジェクトに導入
npm i simplebar
# or
yarn add simplebar
// bundler 環境(例:Vite/webpack)
import 'simplebar/dist/simplebar.min.css';
import SimpleBar from 'simplebar';
基本:属性を付けるだけ(高さは必須)
<div class="card" data-simplebar>
<h3>ニュース</h3>
<p>スクロールテキスト…</p>
<p>スクロールテキスト…</p>
<p>スクロールテキスト…</p>
</div>
<style>
.card{
width: 320px;
height: 180px; /* ← これがないとスクロール領域が生まれない */
border: 1px solid #ddd;
border-radius: 8px;
padding: 12px;
overflow: auto; /* 基本は auto でOK(SimpleBarがラップしてくれる) */
}
</style>
これだけで、ネイティブ同等の操作感を残したまま、見た目が整ったスクロールバーに。
オプションを使う:自動非表示や最小サイズ
data 属性で指定(CDN派におすすめ)
<div class="log"
data-simplebar
data-simplebar-auto-hide="false"
data-simplebar-scrollbar-min-size="20">
<!-- 長文 -->
</div>
<style>
.log{
width: 420px;
height: 240px;
padding: 10px;
border: 1px solid #ccc;
}
</style>
JSで生成(npm or 細かく制御したい場合)
import SimpleBar from 'simplebar';
const el = document.querySelector('.log');
const sb = new SimpleBar(el, {
autoHide: false, // ホバー時のみ表示→falseで常時
scrollbarMinSize: 20, // ハンドルの最小サイズ
scrollbarMaxSize: 48 // ハンドルの最大サイズ
});
// インスタンスにアクセス(後述の再計算などで使う)
console.log(sb);
スクロール位置の制御(「最下部へ」など)
SimpleBarは内部にスクロール用のラッパーを持ちます。
インスタンスからスクロール可能要素を取得して操作します。
// 例:最下部へ移動
function scrollToBottom(sbInstance){
const el = sbInstance.getScrollElement();
el.scrollTop = el.scrollHeight;
}
// 例:先頭へ
function scrollToTop(sbInstance){
sbInstance.getScrollElement().scrollTop = 0;
}
CDN(data属性)で自動初期化した場合でも、要素からインスタンスを参照できます:
const el = document.querySelector('[data-simplebar]');
const sb = SimpleBar.instances.get(el); // 既存インスタンスを取得
scrollToBottom(sb);
動的コンテンツの追加と再計算
通常はMutationObserverで検知してくれますが、一気にDOMを書き換えた後などは手動再計算が確実です。
// 例:ログを追加してから再計算
function appendLog(sbInstance, text){
const content = sbInstance.getContentElement(); // コンテンツ領域
const p = document.createElement('p');
p.textContent = text;
content.appendChild(p);
// レイアウトが大きく変わった際に明示的に再計算
sbInstance.recalculate();
}
ページ全体に適用する場合のコツ
body そのものに適用するのではなく、高さ固定のラッパーを用意するのが定石です。
<body>
<div class="page-scroll" data-simplebar>
<!-- ページの中身全部 -->
</div>
</body>
<style>
html, body { height: 100%; }
.page-scroll{
height: 100%; /* これで“ページ全体のスクロール”に */
overflow: auto;
}
</style>
よく使うカスタマイズ(見た目の調整)
SimpleBarはCSSで見た目を変えられます。
ハンドル色・太さ・角丸などを調整してブランドに寄せましょう。
/* ハンドル(つまみ) */
.simplebar-scrollbar:before{
content: '';
position: absolute;
left: 0; right: 0;
top: 0; bottom: 0;
opacity: 0.6; /* 濃さ */
border-radius: 6px; /* 角丸 */
background: #999; /* 色 */
}
/* トラック(バーのレール) */
.simplebar-track.simplebar-vertical{
width: 10px; /* 太さ */
background: transparent; /* うっすら色を付けたいなら rgba(...) */
margin-right: 2px; /* 余白調整 */
}
/* ホバーで濃くする */
.simplebar-track:hover .simplebar-scrollbar:before{
opacity: 0.95;
}
/* 横スクロール時のトラック(必要なら) */
.simplebar-track.simplebar-horizontal{
height: 10px;
}
メモ:OSやブラウザによってはネイティブのオーバーレイスクロールバーが上に重なることがあります。SimpleBarを使う要素では
overflow: autoを維持しつつ、必ず高さ(もしくはmax-height)を定義して期待どおりの領域を作りましょう。
便利スニペット集
1) 「ログが来たら自動で最下部へ」+手動スクロールを尊重
const el = document.querySelector('.chat');
const sb = SimpleBar.instances.get(el) || new SimpleBar(el);
let stickToBottom = true;
const scrollEl = sb.getScrollElement();
scrollEl.addEventListener('scroll', () => {
const nearBottom = (scrollEl.scrollHeight - scrollEl.scrollTop - scrollEl.clientHeight) < 8;
stickToBottom = nearBottom;
});
function pushMessage(text){
const p = document.createElement('p');
p.textContent = text;
sb.getContentElement().appendChild(p);
sb.recalculate();
if(stickToBottom) scrollEl.scrollTop = scrollEl.scrollHeight;
}
2) 横スクロールのギャラリー
<div class="gallery" data-simplebar>
<div class="row">
<img src="a.jpg"><img src="b.jpg"><img src="c.jpg">
</div>
</div>
<style>
.gallery{
max-width: 100%;
overflow: auto;
white-space: nowrap; /* 横並び */
}
.gallery .row img{
display: inline-block;
width: 240px;
height: 160px;
object-fit: cover;
margin-right: 12px;
border-radius: 8px;
}
.simplebar-track.simplebar-horizontal{ height: 8px; }
</style>
3) 「読み込み中はスクロール無効 → 完了後に有効」
const container = document.querySelector('.panel');
container.style.pointerEvents = 'none'; // 誤操作を防ぐ
container.style.overflow = 'hidden'; // 念のため
// データ取得など非同期処理
fetch('/api/list').then(r => r.json()).then(items => {
const sb = SimpleBar.instances.get(container) || new SimpleBar(container);
const content = sb.getContentElement();
items.forEach(t => {
const li = document.createElement('div');
li.textContent = t.title;
content.appendChild(li);
});
sb.recalculate();
container.style.pointerEvents = '';
container.style.overflow = 'auto';
});
Reactでの最短実装(参考)
公式が simplebar-react も提供しています。
npm i simplebar-react simplebar
import 'simplebar-react/dist/simplebar.min.css';
import SimpleBar from 'simplebar-react';
export default function Panel(){
return (
<SimpleBar style={{ maxHeight: 300 }} autoHide={false}>
<div>行1</div>
<div>行2</div>
<div>行3</div>
</SimpleBar>
);
}
よくあるハマりどころ
- 高さが未指定
→ スクロール領域が生まれず、バーが出ない。heightかmax-heightを付与。 - 入れ子のoverflow
→ 親にも子にもoverflowがあると意図せず二重スクロールに。適用範囲を明確に。 - body 直適用
→ 非推奨。100% 高さのラッパーを用意してそこにSimpleBar。 - 動的更新が大量
→ 原則自動検知。大規模変更後はrecalculate()を呼ぶと安定。 - モバイル慣性スクロール
→ iOS系はネイティブ慣性が効く。必要に応じてoverscroll-behaviorなどでバウンス制御。
まとめ
- SimpleBarはネイティブの強み+綺麗な見た目を両立
data-simplebarを付けるだけでOK、高さ指定がキモ- オプションやCSSで表示タイミング・太さ・色を自在にカスタム
- 動的DOM変更時は
recalculate()を覚えておくと安心


Swiperで作る“寄り→引き”ヒーロースライダー実装ガイド 〜ズーム方向指定・Ken Burns効果・進捗ラインまで〜
1月 6, 2026横スライドしながら拡大するスライド演出の作り方〜ズームインで魅せる、上質なキービジュアル表現〜
12月 24, 2025今日の日付と現在時刻を自動表示!「10月15日10:15 現在」をJavaScriptで実装する方法
10月 15, 2025