OS のテーマ変更を検知して CSS を変える

Recipe ID: front-010

OS のテーマ変更を JavaScript で検知する方法を解説します。

実装方法

window.matchMedia API にリスナーを追加します。
Tauri v1.x 系の一部の API でテーマ取得ができましたが、現在は Web 標準 API を使うのが推奨されます。

// 現在のテーマを取得する関数
function getSystemTheme(): 'dark' | 'light' {
  return window.matchMedia('(prefers-color-scheme: dark)').matches
    ? 'dark'
    : 'light';
}

// テーマ変更を監視する関数
function watchThemeChange(callback: (theme: 'dark' | 'light') => void) {
  const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');

  const handleChange = (e: MediaQueryListEvent) => {
    callback(e.matches ? 'dark' : 'light');
  };

  mediaQuery.addEventListener('change', handleChange);

  // 解除用の関数を返す
  return () => mediaQuery.removeEventListener('change', handleChange);
}

// 使用例
console.log('Initial theme:', getSystemTheme());

const unwatch = watchThemeChange((newTheme) => {
  console.log('Timeout changed to:', newTheme);
  // 例: body のクラスを切り替える
  if (newTheme === 'dark') {
    document.body.classList.add('dark');
  } else {
    document.body.classList.remove('dark');
  }
});

Tauri のウィンドウ背景(Rust 側で設定する WindowBuilder の背景色)は OS テーマに追従しない場合があるため、WebView の背景色を CSS で transparent にして、Rust 側の背景色制御を行う必要があるケースもあります(macOS のバイブランス効果などを使う場合)。