Qlitre's Blog

2022.08.06 Nuxt.js /Vue

Nuxt.jsでダークモードの設定をする方法 (Nuxt2系)

Nuxt.jsでダークモードの切り替えスイッチを導入する方法について簡単にまとめました。

Nuxt バージョン

2.15.7

使用モジュール

@nuxtjs/color-mode
https://color-mode.nuxtjs.org/

こちらですが、最新盤はNuxt3系の対応となっていますので、Nuxt2系でインストールする際はバージョンを指定するようにします。

npm i @nuxtjs/color-mode@2.1.1


Nuxt2系で普通にインストールするとバグってなにもできません。
私はここで時間をけっこう溶かしてしまいました。

インストールしたらnuxt.config.jsに追記しましょう。

{
  buildModules: [
    '@nuxtjs/color-mode'
  ]
}


トグルスイッチの作成

NuxtColorModeはシンプルなモジュールで、$colorMode.preferenceプロパティをグローバルに管理し、html全体にクラスを付与してくれるようです。
this.$colorMode.preference = 'dark'という風にすると、html全体にdark-modeというクラス、this.$colorMode.preference = 'light'
というようにすると、light-modeというクラスが付与されます。

例えばトグルスイッチに応じて、切り替える場合は以下のようになります。

// components/ColorModeSwitch.vue
<template>
    <div>
        <input id="toggle" class="toggle-input" type='checkbox' v-model="isDarkMode" @change="toggleColorMode" />
        <label for="toggle" class="toggle-label" />
    </div>
</template>

<script>
export default {
    data() {
        return {
            isDarkMode: false
        }
    },
    methods: {
        toggleColorMode() {
            if (this.isDarkMode) {
                this.$colorMode.preference = 'dark'
            } else {
                this.$colorMode.preference = 'light'
            }
        }
    }
}
</script>

<style scoped>
.toggle-input {
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    z-index: 5;
    opacity: 0;
    display: none;
}

.toggle-label {
    display: inline-block;
    width: 40px;
    height: 20px;
    background-color: #CBD5E0;
    position: relative;
    border-radius: 46px;
    transition: 0.4s;
    box-sizing: border-box;
    cursor: pointer;
}

.toggle-label::after {
    content: '';
    position: absolute;
    width: 20px;
    height: 20px;
    border-radius: 100%;
    left: 0;
    top: 0;
    z-index: 2;
    background: #fff;
    box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
    transition: 0.4s;
}

.toggle-input:checked+.toggle-label {
    background-color: #718096;
}

.toggle-input:checked+.toggle-label::after {
    left: 20px;
}
</style>


ブール変数isDarkModeにtoggleチェックボックスをバインドさせておきます。
値がチェンジした際に、methodsでモードを切り替えるイメージです。
ここの部分ですね。

<input id="toggle" class="toggle-input" type='checkbox' v-model="isDarkMode" @change="toggleColorMode" />


チェックされるとmethodsのtoggleColorModeが呼ばれ、htmlにクラスを付与します。

methods: {
        toggleColorMode() {
            if (this.isDarkMode) {
                this.$colorMode.preference = 'dark'
            } else {
                this.$colorMode.preference = 'light'
            }
        }
    }


あとはヘッダーコンポーネントに配置します。

// components/Header.vue
<template>
  <header class="header">
    <nuxt-link :to='`/`'>
      <h1 class="site-title">
        Qlitre's Blog
      </h1>
    </nuxt-link>
    <nav class="nav">
      <ul class="main-nav">
        ...
        <li class="nav-item">
          <ColorModeSwitch />
        </li>
      </ul>
    </nav>
  </header>
</template>


トグルボタンをクリックするとトップのhtml要素に<html lang="ja" class="dark-mode">
というようにクラスが付与されます。

後はdark-modeの場合の色分けのスタイルを記述するだけです。
例えば背景色を変える場合。

/* これはライトモードのスタイル */
body {
  background-color: #EDF2F7;
}

/* これはダークモードのスタイル */
.dark-mode body {
  background-color: #1A202C;
}


ここは結構地道な作業となります。