Michael Charles Aubrey

https://MichaelCharl.es/Aubrey

OverlayScrollbarsを使ったTauriアプリのスクロールバーのスタイリング

OverlayScrollbarsを使ったTauriアプリのスクロールバーのスタイリング

Michael Charles Aubrey // Mon Aug 04 2025

サイドプロジェクトで開発している Tauri アプリで、カスタムスクロールバーを動作させるのに苦労していました。過去には単純に::-webkit-scrollbarを使用して成功していましたが、最近はうまく動作しなくなっているようです。GitHub のユーザーx4080さんがoverlayscrollbarsライブラリの使用を提案してくれ、これが非常にうまく機能しました。しかし、セットアップが私が期待していたよりも少し直感的でなかったので、動作させる方法についてクイックガイドをまとめてみました。

この記事では、React と Tailwind CSS でスタイリングされた Tauri アプリで作業します。ただし、必要に応じて適応できると思います。

まず、overlayscrollbarsをインストールしました

npm install overlayscrollbars

次に、importを使って CSS にoverlayscrollbarsのスタイルを含め、カスタムスクロールバー用のスタイルを準備しました。

@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-autooverflow-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 でスクロールバーのスタイリングにうまく機能しています。

Snappad