
OverlayScrollbarsを使ったTauriアプリのスクロールバーのスタイリング
Michael Charles Aubrey // Mon Aug 04 2025
サイドプロジェクトで作っている Tauri アプリで、カスタムスクロールバーがなかなか思うように動かず、苦労していました。以前は::-webkit-scrollbarを指定するだけで済んでいたのですが、最近はどうもうまくいきません。GitHub のx4080さんがoverlayscrollbarsというライブラリを教えてくれて、こちらは問題なく動きました。ただ、設定の手順が思っていたほど分かりやすくなかったので、動かすまでの流れを簡単にまとめておきます。
ここで扱うのは、React で書いて Tailwind CSS でスタイルを当てている Tauri アプリです。別の構成でも、少し手を加えれば応用できるはずです。
まず、overlayscrollbarsをインストールしました
npm install overlayscrollbars
続いて、importでoverlayscrollbarsのスタイルを CSS に読み込み、あわせてカスタムスクロールバー用のスタイルも書きました。
@import "overlayscrollbars/overlayscrollbars.css";
.os-theme-custom.os-scrollbar {
--os-size: 8px;
--os-padding-perpendicular: 0px;
--os-padding-axis: 0px;
}
.os-theme-custom.os-scrollbar .os-scrollbar-track {
background: rgba(120, 90, 200, 0.12);
border-radius: 4px;
}
.os-theme-custom.os-scrollbar .os-scrollbar-handle {
background: rgba(80, 60, 180, 0.45);
border-radius: 4px;
transition: background-color 0.2s ease;
}
.os-theme-custom.os-scrollbar .os-scrollbar-handle:hover {
background: rgba(80, 60, 180, 0.7);
}
スクロールする要素でoverlayscrollbarsを初期化するために、こんなフックを用意しました。この書き方ができるのは Tailwind を使っているおかげで、.overflow-y-autoとoverflow-autoをそのままセレクタとして拾えます。Tailwind を使っていない場合は、別の手を考える必要があります。
import { OverlayScrollbars } from "overlayscrollbars";
import { useEffect } from "react";
export const useOverlayScrollbars = () => {
useEffect(() => {
// すべてのスクロール可能な要素でOverlayScrollbarsを初期化
const initScrollbars = () => {
// メインのスクロール可能なエリアをターゲットにする
const scrollableElements = [
document.body,
document.querySelector('[data-scrollable="true"]'),
...document.querySelectorAll(".overflow-y-auto"),
...document.querySelectorAll(".overflow-auto"),
].filter(Boolean) as Element[];
scrollableElements.forEach((element) => {
const htmlElement = element as HTMLElement;
if (
htmlElement &&
!htmlElement.hasAttribute("data-overlayscrollbars-initialize")
) {
OverlayScrollbars(htmlElement, {
scrollbars: {
theme: "os-theme-custom",
autoHide: "never",
},
});
htmlElement.setAttribute("data-overlayscrollbars-initialize", "true");
}
});
};
// 即座に初期化
initScrollbars();
// DOM変更時に再初期化(動的コンテンツ用)
const observer = new MutationObserver(() => {
setTimeout(initScrollbars, 100);
});
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["class"],
});
return () => {
observer.disconnect();
// すべてのOverlayScrollbarsインスタンスをクリーンアップ
document
.querySelectorAll("[data-overlayscrollbars-initialize]")
.forEach((element) => {
const instance = OverlayScrollbars(element as HTMLElement);
if (instance) {
instance.destroy();
}
});
};
}, []);
};
あとはApp.tsxでこのフックを呼ぶだけです。
import { useOverlayScrollbars } from "./hooks/useOverlayScrollbars";
function App() {
// 初期状態...
// カスタムスクロールバーを初期化
useOverlayScrollbars();
// その他のフック...
return <main>{/* アプリのコンテンツ ... */}</main>;
}
export default App;
これで終わりです。今のところ、サイドプロジェクトの Snappad ではこの方法でスクロールバーがきちんとスタイリングできています。
