1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

補色・類似色を一発生成!カラーバリエーションツールでデザインシステム構築が捗った話

Posted at

u3198448477_A_flat_minimalist_illustration_of_a_color_variati_49e47e2e-bad0-4929-915f-c92731e16f85_1.png

はじめに

デザインシステムやUIを作る時、「この色の補色は?」「もう少し明るいバージョンが欲しい」って思うことありませんか?

色相環を見ながら手動で計算したり、デザインツールで調整したりするのって、結構手間なんですよね。そこで、ベースカラーを選ぶだけで補色・類似色・明度/彩度バリエーションを自動生成するツールを作りました!

image.png

このツールで何ができる?

主な機能

✅ 補色(Complementary)の自動生成
✅ 類似色(Analogous)の複数パターン生成
✅ 明度(Lighter/Darker)のバリエーション
✅ 彩度(Saturation)のバリエーション
✅ ライト/ダークテーマのカラーパレット生成
✅ CSS変数形式で一括コピー
✅ 円形レイアウトで視覚的に色の関係性を確認

使い方

1. ベースカラーを選択

カラーピッカーまたはHEXコード入力で、ベースとなる色を選びます。

例: #3b82f6(青色)

2. バリエーションが自動生成される

選択した色を中心に、円形レイアウトで様々なバリエーションが表示されます。

  • 補色: 180度反対の色
  • 類似色: ±15度、±30度の色
  • 明度調整: ±20%、±40%
  • 彩度調整: ±20%、±40%

3. クリックでコピー

気に入った色をクリックすれば、HEXコードがクリップボードにコピーされます。

4. CSS変数を一括コピー

「CSS変数をコピー」ボタンをクリックすると、全てのバリエーションがCSS変数形式で一括コピーできます。

:root {
  --color-primary: #3b82f6;
  --color-secondary: #60a5fa;
  --color-accent: #f59e0b;
  --color-base: #3b82f6;
  --color-complementary: #f6a43b;
  --color-analogous-1: #3bf6a4;
  --color-analogous-2: #3b82f6;
  /* ... */
}

技術的なポイント

補色の生成ロジック

補色は、色相環で180度反対に位置する色です。HSL色空間を使えば簡単に計算できますね。

const generateComplementary = (baseColor: string) => {
  const rgb = hexToRgb(baseColor)
  const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b)

  // 色相を180度回転
  const complementaryHue = (hsl.h + 180) % 360

  // HSLからRGBへ変換し、HEXに戻す
  const complementary = hslToRgb(complementaryHue, hsl.s, hsl.l)
  return rgbToHex(complementary.r, complementary.g, complementary.b)
}

% 360で0〜360度の範囲に収めるのがポイントです。

類似色の生成

類似色は、色相を少しずらした色です。±15度、±30度でバリエーションを作成しています。

const generateAnalogous = (baseHue: number, offset: number) => {
  return (baseHue + offset + 360) % 360
}

// 使用例
for (let i = -30; i <= 30; i += 15) {
  if (i === 0) continue
  const analogousHue = (hsl.h + i + 360) % 360
  const analogousColor = hslToRgb(analogousHue, hsl.s, hsl.l)
  variations.push(rgbToHex(analogousColor.r, analogousColor.g, analogousColor.b))
}

明度・彩度の調整

HSL形式の強みを活かして、LightnessとSaturationを調整します。

// 明度のバリエーション(±20%, ±40%)
for (let i = -40; i <= 40; i += 20) {
  if (i === 0) continue
  const adjustedL = Math.max(0, Math.min(100, hsl.l + i))
  const tonedColor = hslToRgb(hsl.h, hsl.s, adjustedL)
  variations.push({
    name: `${i > 0 ? 'Lighter' : 'Darker'} ${Math.abs(i)}%`,
    hex: rgbToHex(tonedColor.r, tonedColor.g, tonedColor.b)
  })
}

// 彩度のバリエーション(±20%, ±40%)
for (let i = -40; i <= 40; i += 20) {
  if (i === 0) continue
  const adjustedS = Math.max(0, Math.min(100, hsl.s + i))
  const saturatedColor = hslToRgb(hsl.h, adjustedS, hsl.l)
  variations.push({
    name: `Saturation ${i > 0 ? '+' : ''}${i}%`,
    hex: rgbToHex(saturatedColor.r, saturatedColor.g, saturatedColor.b)
  })
}

Math.max(0, Math.min(100, value))で0〜100%の範囲に制限しています。

円形レイアウトの実装

色の関係性を視覚的に理解しやすくするため、円形レイアウトを採用しました。

const generateCircleLayout = (variations: ColorVariation[]) => {
  return variations.map((variation, index) => {
    const angle = (index * 360) / variations.length - 90 // -90で上から開始
    const radius = 200 // 円の半径

    const x = Math.cos((angle * Math.PI) / 180) * radius
    const y = Math.sin((angle * Math.PI) / 180) * radius

    return {
      ...variation,
      style: {
        transform: `translate(calc(-50% + ${x}px), calc(-50% + ${y}px))`
      }
    }
  })
}

三角関数を使って各色の配置座標を計算しています。

レスポンシブ対応

画面サイズに応じて円の半径を調整し、モバイルでも見やすくしました。

const [windowWidth, setWindowWidth] = useState(0)

useEffect(() => {
  const handleResize = () => setWindowWidth(window.innerWidth)
  handleResize()
  window.addEventListener('resize', handleResize)
  return () => window.removeEventListener('resize', handleResize)
}, [])

const radius = windowWidth < 640 ? 120 : windowWidth < 768 ? 160 : 200

ライト/ダークテーマのパレット生成

ベースカラーから、テーマに適したカラーパレットを自動生成します。

const generatePalette = (theme: 'light' | 'dark', baseColor: string) => {
  const rgb = hexToRgb(baseColor)
  const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b)

  if (theme === 'light') {
    return {
      primary: baseColor,
      secondary: hslToHex((hsl.h + 30) % 360, hsl.s, hsl.l),
      accent: hslToHex((hsl.h + 180) % 360, hsl.s, hsl.l),
      background: '#FFFFFF',
      surface: '#F5F5F5',
      text: '#212121',
      textSecondary: '#757575',
      border: '#E0E0E0'
    }
  } else {
    return {
      primary: baseColor,
      secondary: hslToHex(
        (hsl.h + 30) % 360,
        Math.max(hsl.s - 10, 0),
        Math.max(hsl.l - 10, 0)
      ),
      accent: hslToHex((hsl.h + 180) % 360, hsl.s, hsl.l),
      background: '#121212',
      surface: '#1E1E1E',
      text: '#FFFFFF',
      textSecondary: '#B0B0B0',
      border: '#333333'
    }
  }
}

ダークテーマでは、セカンダリカラーの彩度と明度を少し下げて、目に優しい配色にしています。

こんな時に便利

  • デザインシステム構築: プライマリカラーから一貫性のある配色を生成
  • UIコンポーネント作成: ボタンのホバー状態(少し明るい色)を簡単に作成
  • アクセシビリティ対応: 明度を調整してコントラスト比を確認
  • ブランドカラー展開: 1色から複数のバリエーションを生成
  • テーマ切り替え: ライト/ダークテーマ用のパレットを同時に確認

実装例:ボタンコンポーネント

このツールで生成した色を使って、ボタンのホバー状態を実装する例です。

:root {
  --color-primary: #3b82f6;
  --color-primary-light: #60a5fa; /* Lighter 20% */
  --color-primary-dark: #2563eb;  /* Darker 20% */
}

.button {
  background-color: var(--color-primary);
  transition: background-color 0.2s;
}

.button:hover {
  background-color: var(--color-primary-light);
}

.button:active {
  background-color: var(--color-primary-dark);
}

Known Issues & 今後の予定

現在、以下の機能を検討中です:

  • トライアド配色(120度間隔)の生成
  • テトラード配色(90度間隔)の生成
  • アクセシビリティチェック(コントラスト比計算)
  • カラーパレットのエクスポート(JSON/SCSS形式)
  • URLでカラーパレットを共有できる機能(現在実装済み)

まとめ

色彩理論に基づいたカラーバリエーションを自動生成できるツールを作りました。HSL色空間を活用することで、補色や類似色の計算が数学的に簡単になり、デザインシステム構築が格段に楽になります。

全てブラウザで完結するので、インストール不要で今すぐ使えます。デザイン作業の効率化にぜひ使ってみてください!

ツールはこちら: https://tools.easegis.jp/ja/tools/image/color-variations

参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?