banner
innei

innei

写代码是因为爱,写到世界充满爱!
github
telegram
twitter

Tailwind の組み込みカラーをダークモードに対応させる

最近 xLog にダークモードのサポートを追加しましたが、xLog の開発時にダークモード用の設定がされていなかったため、色の値が固定されていたり、CSS 変数の色の値が使用されていませんでした。そして、xLog は偶然にも Tailwind を使用しており、ほとんどすべての色の適用シーンで Tailwind に付属の色値を使用していますが、Tailwind 自体の色値は固定の値であり、ダークモードに応じて色値を切り替えることはサポートされていません。

そこで、内蔵の色がダークモードかどうかに応じて切り替わるようにするというアイデアが浮かびました。

まず最初に、Tailwind を再構成し、元のすべての色を上書きして、固定の値をすべて CSS 変数に書き換える必要があります。変数のプレフィックスはカスタマイズ可能で、衝突しないようにすれば大丈夫です。ここでは仮に tw-colors-i とします。例えば、以下のような色値の設定が必要です:

// tailwind.config.ts
module.exports = {
  theme: {
    colors: {
      slate: {
        50: 'rgb(var(--tw-colors-i-slate-50))',
        100: 'rgb(var(--tw-colors-i-slate-100))',
        // ...
      },
    },
  },
}

しかし、上記の書き方では Tailwind の色に不透明度を持たせる機能がサポートされていないため、少し修正が必要です。

// tailwind.config.ts
module.exports = {
  theme: {
    colors: {
      slate: {
        50: 'rgba(var(--tw-colors-i-slate-50), <alpha-value>)',
        100: 'rgba(var(--tw-colors-i-slate-100), <alpha-value>)',
        // ...
      },
    },
  },
}

<alpha-value> を追加して、Tailwind が対応する不透明度を置き換えられるようにします。ここでは rgba を使用しているため、後で色変数を定義する際には、Hex タイプの色値を使用せず、以下のような形式 --tw-colors-i-slate-50: 248, 250, 252; を使用する必要があります。

次に、反転色の問題です。Tailwind 3.3 以上のバージョンでは、内蔵色は 50 から始まり 950 で終わります(3.2 バージョンには 950 がありません)。明るい色に対して暗い色が対応し、合計は 1000 になります。例えば、slate-50 に対応する暗い色は slate-950 で、 90+950=1000 となります。この考え方に基づいて、暗い色のすべての色値を生成するスクリプトを書くことができます。

コードはここには貼りませんが、Crossbell-Box/xLog で見ることができます。使用する場合は、生成された CSS パスと Tailwind 色値設定のパスを変更するだけで済みます(Tailwind >= 3.3)。

生成された CSS 色変数の定義は以下のようになります(部分的に抜粋、完全なものは Crossbell-Box/xLog で確認できます):

:root {
  --tw-colors-i-slate-50: 248, 250, 252;
  --tw-colors-i-slate-100: 241, 245, 249;
  --tw-colors-i-slate-200: 226, 232, 240;
  --tw-colors-i-slate-300: 203, 213, 225;
  --tw-colors-i-slate-400: 148, 163, 184;
  --tw-colors-i-slate-500: 100, 116, 139;
}

html.dark {
  --tw-colors-i-slate-50: 2, 6, 23;
  --tw-colors-i-slate-100: 15, 23, 42;
  --tw-colors-i-slate-200: 30, 41, 59;
  --tw-colors-i-slate-300: 51, 65, 85;
  --tw-colors-i-slate-400: 71, 85, 105;
  --tw-colors-i-slate-500: 100, 116, 139;
}

html.light {
  --tw-colors-i-slate-50: 248, 250, 252;
  --tw-colors-i-slate-100: 241, 245, 249;
  --tw-colors-i-slate-200: 226, 232, 240;
  --tw-colors-i-slate-300: 203, 213, 225;
  --tw-colors-i-slate-400: 148, 163, 184;
  --tw-colors-i-slate-500: 100, 116, 139;
}

@media (prefers-color-scheme: dark) {
  html:not(.light) {
    --tw-colors-i-slate-50: 2, 6, 23;
    --tw-colors-i-slate-100: 15, 23, 42;
    --tw-colors-i-slate-200: 30, 41, 59;
    --tw-colors-i-slate-300: 51, 65, 85;
    --tw-colors-i-slate-400: 71, 85, 105;
    --tw-colors-i-slate-500: 100, 116, 139;
  }
}

@media (prefers-color-scheme: light) {
  html:not(.dark) {
    --tw-colors-i-slate-50: 248, 250, 252;
    --tw-colors-i-slate-100: 241, 245, 249;
    --tw-colors-i-slate-200: 226, 232, 240;
    --tw-colors-i-slate-300: 203, 213, 225;
    --tw-colors-i-slate-400: 148, 163, 184;
    --tw-colors-i-slate-500: 100, 116, 139;
  }
}

この CSS では、システムが暗色か明色か、また html.light html.dark に基づいて明暗色を決定しています。

同時に Tailwind 色設定も生成します:

// tw-colors.js
export default {
  slate: {
    50: "rgba(var(--tw-colors-i-slate-50), <alpha-value>)",
    100: "rgba(var(--tw-colors-i-slate-100), <alpha-value>)",
    200: "rgba(var(--tw-colors-i-slate-200), <alpha-value>)",
    300: "rgba(var(--tw-colors-i-slate-300), <alpha-value>)",
    400: "rgba(var(--tw-colors-i-slate-400), <alpha-value>)",
    500: "rgba(var(--tw-colors-i-slate-500), <alpha-value>)",
    600: "rgba(var(--tw-colors-i-slate-600), <alpha-value>)",
    700: "rgba(var(--tw-colors-i-slate-700), <alpha-value>)",
    800: "rgba(var(--tw-colors-i-slate-800), <alpha-value>)",
    900: "rgba(var(--tw-colors-i-slate-900), <alpha-value>)",
    950: "rgba(var(--tw-colors-i-slate-950), <alpha-value>)",
  },
  // ...
  inherit: "inherit",
  current: "currentColor",
  transparent: "transparent",
  black: "rgba(var(--tw-colors-i-black), <alpha-value>)",
  white: "rgba(var(--tw-colors-i-white), <alpha-value>)",
}

プロジェクト内で、生成された CSS をインポートし、Tailwind 設定で色を上書きします。

// tailwind.config.js
const twColors = require("./tw-colors")
const alwaysColor = require("tailwindcss/colors")

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.tsx"],
  darkMode: ['class', 'html.dark'],
  theme: {
    colors: twColors,
    extend: {
    	colors: {
    	  always: alwaysColor
  		}
  	}
	}
}

ここでオプション設定として always を定義します。always の色は依然として自動的に提供される固定色値です。必要に応じて使用できます。

darkMode を定義する必要があるかどうかは、現在はオプションになりました。Tailwind が提供する dark-mode: を使用する必要がある場合は、オンにする必要があります。しかし、すべてが動的色値になったので、使用ニーズに応じてオンオフを決めれば良いでしょう。


欠点について:

  • 大量の CSS 変数が導入され、無用な変数はコンパイル時に削除できません。

より良い解決策?

Tailwind に PR を送ることです。色の多重定義をサポートするように、以下のようにします:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./src/**/*.tsx'],
  theme: {
    colors: {
      blue: {
        50: {
          light: '#123',
          dark: '#321',
        },
      },
    },
  },
}

Tailwind の仲間がこの提案を見てくれることを願っています。

最後に xLog をお勧めします。こんなに使いやすいブログプラットフォーム、まだ試していないのですか?

そういえば、私が作った Mix Space も今や xLog への同期をサポートしています。ぜひ試してみてください。

この記事は Mix Space によって xLog に同期更新されました。元のリンクは https://innei.ren/posts/programming/tailwind-built-in-colors-dark-mode

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。