Skip to content

Vitepress ナビゲーションバーのフォント切り替え

作者:Lee 等
最后更新:

実現原理

CSS 変数を定義し、ナビゲーションバーボタンがクリックされた時に CSS 変数を更新する

ボタンの追加

ts
// docs/.vitepress/config.ts
// nav ...
{
    text: "フォント切替",
    items: [
      {
        text: "霞鶩文楷",
        link: "#", // リンク遷移不要なので空リンクを使用
      },
      {
        text: "霞鶩新晰黒",
        link: "#",
      },
    ],
  },

CSS でフォントをインポートする

css
@font-face {
  font-family: '霞鶩文楷';
  src: url('/LXGWWenKai-Regular.ttf') format('truetype');
}

CSS に CSS 変数を導入する

--main-font が値を割り当てられる前は初期値が空なので、代替フォントオプションを「デフォルトフォント」として利用できます

css
:root {
/* var(--main-font, '代替フォント') */
--vp-font-family-base: var(--main-font, '霞鶩文楷');/* テキストフォント */
--vp-font-family-mono: "霞鶩文楷-等幅";/* コードフォント */
}

ボタンを監視し、フォント名を CSS 変数に渡す

ここでは新しく js スクリプトを作成し、ボタンの監視と CSS 変数の更新を行います

js
// docs/.vitepress/theme/fontSwitcher.js
export const fontMap = {
  '霞鶩文楷': "'霞鶩文楷', serif", // 'ボタン名':'フォント名',代替フォント(任意)
  '霞鶩新晰黒': "'霞鶩新晰黒', serif",
  };

  // フォント切替関数
  export const switchFont = (font) => {
    document.documentElement.style.setProperty('--main-font', fontMap[font]);
  };

  // 全体フォント切替イベントリスナーを追加
  export const addFontSwitchListener = () => {
    // 通常Vitepressのドロップダウンメニュー内容はspanタグでラップされているため、('.items span') に置き換えてください。当サイトはaタグなのでaを使用
    const fontSwitchItems = document.querySelectorAll('.items a'); // 全てのナビゲーションaタグを取得
    // このログはデバッグ用。うまくいかない場合は下記のコメントを外してください
    // console.log(`見つかったフォント切替項目 ${fontSwitchItems.length} 件`);
    fontSwitchItems.forEach(item => {
      item.addEventListener('click', (e) => {
        e.preventDefault();
        const target = e.target;
        const selectedFont = target.innerText; // クリックしたフォント名を取得
        // console.log(`${selectedFont}`);
        switchFont(selectedFont); // フォント切替
      });
    });
};

上記は誤った例で、Vitepress のモバイルビューでは折りたたみナビゲーションがデフォルトで折りたたみ状態となっており、ユーザーがナビゲーションを展開した時に初めて関連リソースが読み込まれるため、リスナーがこの前に作成されてしまい正常に監視できません。

正しい例

ts
export const fontMap = {
  // フォントマッピングテーブル
  '霞鶩文楷': 'LXGW WenKai',
  '霞鶩文楷 Mono': 'LXGW WenKai Mono',
  '霞鶩新晰黒': 'LXGW Neo XiHei',
  '新晰黒 Code': 'NeoXiHei Code',
  'デフォルトフォント': 'system-ui',
  '更紗黒体': 'Sarasa UI SC',
  '思源宋体': 'Source Han Serif CN',
  '黒体': 'sans',
  '宋体': 'serif',
};

// フォント切替関数
export const switchFont = (font) => {
  document.documentElement.style.setProperty('--main-font', fontMap[font]);
};

// 全体フォント切替イベントリスナーを追加
export const addFontSwitchListener = () => {
  // ハンバーガーメニューを選択
  const hamburger = document.querySelector('.VPNavBarHamburger');
  const fontSwitchItems = document.querySelectorAll('.items a'); // 全てのナビゲーションaタグを取得
      // console.log(`見つかったフォント切替項目 ${fontSwitchItems.length} 件`);

      fontSwitchItems.forEach(item => {
        item.addEventListener('click', (e) => {
          e.preventDefault();
          const target = e.target;
          const selectedFont = target.innerText; // クリックしたフォント名を取得
          // console.log(`${selectedFont}`);
          switchFont(selectedFont); // フォント切替
        });
      });

  // ハンバーガーメニューのイベントリスナーを追加
  if (hamburger) {
    hamburger.addEventListener('click', () => {
      // ハンバーガーメニュー展開時にフォント切替イベントリスナーを追加
      const fontSwitchItems = document.querySelectorAll('.items a'); // 全てのナビゲーションaタグを取得
      // console.log(`見つかったフォント切替項目 ${fontSwitchItems.length} 件`);

      fontSwitchItems.forEach(item => {
        item.addEventListener('click', (e) => {
          e.preventDefault();
          const target = e.target;
          const selectedFont = target.innerText; // クリックしたフォント名を取得
          // console.log(`${selectedFont}`);
          switchFont(selectedFont); // フォント切替
        });
      });
    });
  }
};

index.ts/index.js でスクリプトをインポートする

ts
// docs/.vitepress/theme/index.ts
// https://vitepress.dev/guide/custom-theme
import PtjsTheme from '@project-trans/vitepress-theme-project-trans/theme'
import { onMounted } from 'vue'
import { addFontSwitchListener } from './fontSwitcher' // スクリプトをインポート

import 'uno.css'
import './style.css'

export default {
  extends: PtjsTheme, // こちらはカスタムテーマをインポート
  setup() {
    onMounted(() => {
      addFontSwitchListener(); // フォント切替イベントリスナー追加
    });
  },
}

結び

うまく動作しない場合は、コンソールで css ファイルのパスが正しいか、スクリプトが正常に実行されているか、ボタン内容を正しく取得できているか(コメント参照)を必ずご確認ください。

页面历史