🫧

Tailwind CSS×カスタムカラーパレット:ハードコードしないテクニック!

2025/02/17に公開2

1. はじめに:Tailwindでのカラーパレット管理

Tailwind CSSは、効率的にUIを構築するための強力なツールです。
多くのプロジェクトでは、tailwind.config.ts で独自のカラーパレットを定義し、デザインの一貫性を保っています。
例えば、以下のように定義すれば、プロジェクト全体で使えるカラーパレットが実現できます。

// tailwind.config.ts の一例
import type { Config } from 'tailwindcss'
import scrollbarHide from 'tailwind-scrollbar-hide'

const config: Config = {
  content: ['./src/**/*.{js,ts,jsx,tsx,mdx}'],
  theme: {
    extend: {
      colors: {
        ap: {
          gray: {
            DEFAULT: '#9f9f9f',
            0: '#fff',
            50: '#fafafa',
            100: '#f5f5f5',
            200: '#efefef',
            300: '#e1e1e1',
            400: '#bebebe',
            500: '#9f9f9f',
            600: '#767676',
            700: '#626262',
            800: '#434343',
            900: '#222',
            1000: '#000',
          },
        },
      },
    },
  },
}
export default config

クラス名に bg-ap-gray-300border-ap-gray と指定するだけで、手軽に使えるのはとても魅力的です。

使用例

👆のように定義されているとき、classNameに次のように指定することでカラーを使用することができます。
Tailwindカラーパレットの表示例

// ap-grayなど数値suffixがない場合はDEFAULTが当てられます
  <div className="bg-ap-gray-300 border border-lg border-ap-gray">
    <span className="text-ap-gray-1000 p-4">
      hogehoge
    </span>
  </div>

2. 問題:SVGやfill・strokeでの苦労

しかし、ここで一つのジレンマが発生します。
ボタンや背景以外に、SVGの fillstroke、もしくはJavaScript内で直接カラーコードを指定しなければならない場面では、
毎回 #9f9f9f のようなカラーコードを手入力する必要があり、保守性が低下してしまいます。

  • 問題点:
    • 定義済みのカラーパレットが活かしきれない
    • カラーコードの重複記述で、変更時に手間がかかる

3. 解決策:Tailwindの設定からカラーコードを動的に取得する

ここで登場するのが、Tailwindのカラーパレット設定をそのまま利用してカラーコードを返すユーティリティ関数です。
この仕組みを導入すれば、SVGやその他のコンポーネントでも、わざわざカラーコードをハードコーディングする必要がなくなります。

実装例:utils/tailwindColor.ts

import resolveConfig from 'tailwindcss/resolveConfig'
import tailwindConfig from '../../tailwind.config'

const fullConfig = resolveConfig(tailwindConfig)

export const getTailwindColor = (colorPath: string) => {
  // 'ap-gray-600' や 'ap-gray-DEFAULT' の形式で指定
  const colors = fullConfig.theme.colors
  return colorPath.split('-').reduce((acc: any, key) => acc[key], colors)
}

この関数は、tailwind.config.ts に定義されたカラーパレットを元に、
指定したパス文字列(例: 'ap-gray-600')を辿ってカラーコード(例: #767676)を返してくれます。

利用例

const color = getTailwindColor('ap-gray-600') // → #767676 を返す
const color2 = getTailwindColor('ap-gray-DEFAULT') // → #9f9f9f を返す

また、以下のようにSVGコンポーネント内で活用することで、Tailwindで設定したカラーを容易に反映できます。(Reactのコンポーネントを例にとっています)

share-icon.tsx

import { getTailwindColor } from 'utils/tailwindColor'

type IconProps = {
  fill?: string
  className?: string
}

const ShareIcon = ({ fill = 'ap-black-300', className = '' }: IconProps) => {
  const fillColor = getTailwindColor(fill)
  return (
    <svg
      width="25"
      height="25"
      viewBox="0 0 25 25"
      fill="none"
      xmlns="http://www.w3.org/2000/svg"
      className={className}
    >
      <g clipPath="url(#clip0_400_3071)">
        <path
          d="M16.5 5.5L15.08 6.92L13.49 5.33V16.5H11.51V5.33L9.92 6.92L8.5 5.5L12.5 1.5L16.5 5.5ZM20.5 10.5V21.5C20.5 22.6 19.6 23.5 18.5 23.5H6.5C5.39 23.5 4.5 22.6 4.5 21.5V10.5C4.5 9.39 5.39 8.5 6.5 8.5H9.5V10.5H6.5V21.5H18.5V10.5H15.5V8.5H18.5C19.6 8.5 20.5 9.39 20.5 10.5Z"
          fill={fillColor}
        />
      </g>
      <defs>
        <clipPath id="clip0_400_3071">
          <rect
            width="24"
            height="24"
            fill="white"
            transform="translate(0.5 0.5)"
          />
        </clipPath>
      </defs>
    </svg>
  )
}

export default ShareIcon

次のようにアイコンにfillを渡すだけで、色分けできるようになりました!

image.png

    <ShareIcon />
    <ShareIcon fill='ap-red-700' />
    <ShareIcon fill='ap-blue-700' />

4. なぜこのアプローチが有効なのか

  • 一元管理:
    Tailwindの設定に沿ったカラーパレットを、そのまま各コンポーネントで再利用できるため、メンテナンスが楽になります。

  • 変更が容易:
    カラーの変更が必要な場合、tailwind.config.ts のみ修正すれば全体に反映されるため、開発スピードと正確性が向上します。

  • 再利用性:
    コンポーネント毎に異なるカラーコードを記述する必要がなく、コードの再利用性が向上します。


5. まとめ

Tailwind CSSでカラーパレットを一元管理しつつ、SVGやその他の場面で同一のカラーを使い回すためのこのテクニックは、コードの効率化とコードの保守性向上に貢献します。
この仕組みを採用することで、デザインの一貫性を保ちながら開発できるとおもいます。

ぜひ、感想や改善案をコメントで教えてください!
ストックついでに いいねもいただけますと幸いです!

Discussion

なにみるなにみる

なんと、そういうアプローチがあったのですね!
ありがとうございます!
試してみます!