Hex vs RGB vs HSL:開発者のためのカラーフォーマット解説

8 min2026年5月20日

Hex vs RGB vs HSL:各フォーマットが表すもの

Hex・RGB・HSLの議論は、どれが「優れている」かではありません。同じ色を3通りで書いているだけです。#FF6B35 と rgb(255, 107, 53) と hsl(16, 100%, 60%) は同一の色です。違いは色をどのように成分に分解するかで、これがプログラムで色を読み取り、変更し、生成する際の容易さに影響します。

Hex(#RRGGBB)は赤・緑・青を6桁の16進数にパックします。各ペアは00(なし)からFF(最大)の範囲です。コンパクトで普遍的——すべてのブラウザ、デザインツール、APIがHexを理解します。欠点は人間が読みにくいこと。#2E86ABが中程度の青だと見ただけでわかりますか?ほとんどの人にはわかりません。Hexは保存と通信のためのもので、色について考えるためのものではありません。

RGB(赤、緑、青)はHexと同じですが10進数(各チャンネル0-255)です。rgb(46, 134, 171)は#2E86ABよりやや読みやすい——青(171)が支配的で、緑(134)が中程度、赤(46)が低いことがわかります。しかし「これを20%明るくして」や「オレンジ寄りにして」といった質問に答えるのは難しいです。明度や色相がRGBでは明示的でないからです。

HSL(色相、彩度、明度)は色を3つの直感的な次元に分離します。色相は色相環上の位置(0°=赤、120°=緑、240°=青)。彩度は鮮やかさ(0%=グレー、100%=鮮明)。明度は明るさ(0%=黒、50%=純色、100%=白)。明るくしたい?Lを上げる。落ち着いた色にしたい?Sを下げる。補色が欲しい?Hに180°足す。これがHSLがプログラムによる色操作で勝る理由です。

各フォーマットの使い分け(実践ルール)

Hexを使う場面:CSS変数、デザイントークン、ブランドカラー定義、APIレスポンス、データベース保存。最もコンパクトなテキスト表現(6-8文字)で、普遍的にサポートされています。デザイナーからカラースペックを受け取るとき、Hexで来ます。設定ファイルに色を保存するとき、Hexを使いましょう。

RGBを使う場面:Canvas操作、WebGL、画像処理、個別のカラーチャンネルを操作するあらゆる場面。Canvas APIはRGBで動作します。2色のブレンドはRGBで簡単(各チャンネルの平均)。アルファ合成の公式はRGB値を使います。ピクセルレベルの作業をするなら、RGBで考えましょう。

HSLを使う場面:カラーパレットの生成、ホバー/アクティブ状態の作成、テーマ構築、ユーザーが色を選ぶUI。「10%暗く」はHSLなら簡単(Lから10引く)。「同じ色で落ち着いた感じ」も簡単(Sを下げる)。5色を均等に生成するのも簡単(360°を5で割ってその色相を使う)。color-pickerツールは3つのフォーマットを同時に表示するので、関係性が見えます。

OKLCHを使う場面:知覚的に均一な色操作(CSS Color Level 4で新登場)。HSLには欠点があります——hsl(60, 100%, 50%)(黄色)はhsl(240, 100%, 50%)(青)より遥かに明るく見えますが、L値は同じです。OKLCHは知覚的に均一な明度でこれを修正します。2026年にデザインシステムを構築していて、色相間で一貫した知覚的明るさが必要なら、OKLCHが正しい選択です。構文はoklch(lightness chroma hue)で、lightnessは0-1、chromaは0-0.4(おおよそ)、hueは0-360°です。

/* Same color in different formats */
.button {
  /* All identical: a warm orange */
  color: #FF6B35;
  color: rgb(255, 107, 53);
  color: hsl(16, 100%, 60%);
  color: oklch(0.7 0.18 45);
}

/* HSL makes variations trivial */
.button:hover {
  /* 10% darker: just reduce lightness */
  background: hsl(16, 100%, 50%);
}
.button:active {
  /* 20% darker */
  background: hsl(16, 100%, 40%);
}
.button--muted {
  /* Same hue, less saturated */
  background: hsl(16, 40%, 60%);
}

/* Generating a palette with HSL */
:root {
  --primary: hsl(220, 70%, 50%);
  --primary-light: hsl(220, 70%, 70%);
  --primary-dark: hsl(220, 70%, 30%);
  --complement: hsl(40, 70%, 50%); /* +180° hue */
}

コードでの色操作

暗く/明るく:HSLではL値を減らす/増やすだけです。hsl(200, 80%, 50%)を20%暗くするとhsl(200, 80%, 30%)になります。Hex/RGBでは、まずHSLに変換し、変更してから戻す必要があります。これがすべてのCSS-in-JSライブラリ(styled-components、emotion)が内部的にHSLで動作するdarken()やlighten()ヘルパーを提供する理由です。

不透明度/透明度:アルファチャンネルを追加します。Hexは8桁を使います(#FF6B3580 = 50%不透明度)。RGBはrgba(255, 107, 53, 0.5)になります。HSLはhsla(16, 100%, 60%, 0.5)になります。アルファ値は0(完全透明)から1(完全不透明)の範囲です。注意:8桁HexはIE11でサポートされていません(まだ気にするなら)が、rgba()はどこでも動きます。

色の混合:最もシンプルなアプローチはRGBでの線形補間です。赤50%と青50%を混ぜる:r=(255+0)/2=128, g=(0+0)/2=0, b=(0+255)/2=128 → rgb(128, 0, 128) = 紫。CSSにはcolor-mix()があります:color-mix(in srgb, red 50%, blue)がこれをネイティブに行います。知覚的により良い混合にはOKLCH空間で補間します——RGB混合は濁った中間色を生むことがあります。

アクセシブルな色ペアの生成:前景と背景のWCAGコントラスト比を計算します。公式は相対輝度を使います:L = 0.2126×R + 0.7152×G + 0.0722×B(R, G, BはsRGBから線形化)。コントラスト比 = (L1 + 0.05) / (L2 + 0.05)、L1 > L2。WCAG AAは通常テキストで4.5:1、大きなテキストで3:1を要求します。color-pickerツールはこれを自動計算します。

CSSカラー関数(モダンなアプローチ)

CSS相対カラー(2024年以降):color: hsl(from var(--brand) h s calc(l - 20%))でJavaScriptなしにブランドカラーの暗いバージョンを作れます。"from"キーワードがソースカラーを成分に分解し、calc()で変更できます。これにより多くの場合、プリプロセッサのカラー関数が不要になります。

color-mix()(2023年からサポート):color-mix(in oklch, var(--primary) 70%, white)はプライマリカラーの70%と白の30%を混ぜてティントを生成します。"in oklch"の部分は補間のカラースペースを指定します——oklchはほとんどの色の組み合わせでsrgbより自然な混合を生みます。

oklch()関数:oklch(0.7 0.15 250)は明度(0-1)、彩度(0-0.4程度、どれだけカラフルか)、色相(0-360°)を指定します。HSLと違い、OKLCHの等しい明度値は人間の目に実際に同じ明るさに見えます。これはデータビジュアライゼーションで重要です——同じ目立ち方の5色が必要なら、同じL値のOKLCHで実現できますが、HSLではできません。

実践的なヒント:デザイントークンはHexで定義し(互換性とデザイナーへの引き渡しのため)、派生色(ホバー状態、無効状態、フォーカスリング)にはCSSでHSLまたはOKLCHを使いましょう。これで両方の良いところが得られます:デザイナーが認識する安定した参照色と、JavaScriptなしの簡単なプログラム的バリエーションです。

アクセシビリティとコントラスト比

WCAG 2.1のコントラスト要件:通常テキスト(18px未満または14px太字未満)で4.5:1、大きなテキスト(18px以上または14px太字以上)で3:1、UIコンポーネントとグラフィカルオブジェクトで3:1。これは提案ではなく、多くの法域で法的要件です(米国のADA、EUのEN 301 549)。コントラスト不足は一部のユーザーが文字通りコンテンツを読めないことを意味します。

よくある失敗:白背景に薄いグレーのテキスト(#999 on #fff = 2.85:1、AA不合格)、薄すぎるプレースホルダーテキスト、読めない無効ボタンテキスト、周囲のテキストとコントラストが取れていないカラーリンク。修正は通常シンプルです——テキストを暗くするか背景を明るくして4.5:1に達するまで調整します。color-pickerツールは色を調整しながらコントラスト比を表示します。

ダークモードの罠:色を反転してもコントラスト比は保持されません。#333 on #fff(12.6:1)を反転して#ccc on #000は13.1:1——問題なし。しかし#666 on #fff(5.7:1)を反転して#999 on #000は5.1:1——まだ合格ですがギリギリ。ライトモードで合格する色の組み合わせが、反転後のダークモードで不合格になることもあります。各モードで個別にコントラスト比を確認してください。

WCAGを超えて:男性の約8%、女性の約0.5%が何らかの色覚異常を持っています。情報を伝えるのに色だけに頼らないでください(エラー/成功に赤/緑を使うのが典型的な失敗)。色と一緒にアイコン、パターン、テキストラベルを使いましょう。色覚異常シミュレーターでUIをテストしてください——Chrome DevToolsに内蔵されています(レンダリングパネル → 視覚障害のエミュレート)。

sRGBを超えるカラースペース

sRGBはWebのデフォルトカラースペースです。可視色の約35%をカバーします。モダンなディスプレイ(P3、2016年以降のiPhoneと2015年以降のMacBookで使用)はsRGBより約25%多くの色を表示できます。Hex/RGBだけを使っているなら、sRGBに制限されています。より広い色域にアクセスするには、CSSでcolor(display-p3 1 0.5 0)を使います。

広色域が重要な場面:鮮やかな写真、sRGBでは「平坦」に見えるブランドカラー(特に彩度の高い赤と緑)、色を「際立たせたい」デザイン。重要でない場面:テキスト、UIクローム、背景、微妙な色の違いが重要でないもの。

フォールバック戦略:@supports (color: color(display-p3 1 0 0))でP3サポートを検出し、sRGBフォールバックを提供します。またはcolor()関数でフォールバック:color: #ff6b35; color: color(display-p3 1 0.45 0.2); ——display-p3を理解しないブラウザは2番目の宣言を無視してHex値を使います。

デザイナーではない開発者へ:広色域カラーについて考える必要はおそらくありません。sRGBは一般的なUIデザインのすべての色をカバーします。広色域は写真サイト、ECの商品画像、ブランド重視のマーケティングページに関連します。デザイナーがP3カラーについて言及していなければ、sRGBのHex/RGB/HSLを使ってコントラスト比を正しく設定することに集中しましょう。広色域のパフォーマンスコストはゼロです——CSSでのカラースペース宣言が違うだけで、レンダリングのオーバーヘッドではありません。

Web開発でよくある色の間違い

間違い1:CSSカスタムプロパティを使わずに色をハードコーディング。ブランドの青が47箇所に出現していてデザイナーが変更したら、47回の検索置換です。色は一度だけ--color-primary: hsl(220, 70%, 50%)として定義し、どこでも参照しましょう。これでダークモードも簡単になります——.darkクラスやメディアクエリの下でカスタムプロパティを再定義するだけです。

間違い2:ホバー状態にHSL明度ではなくopacityを使う。色付きボタンにopacity: 0.8を設定すると背景が透けて、予測不能な色になります。代わりに同じ色のやや暗い/明るいバージョンを使いましょう:ホバーにbackground: hsl(220, 70%, 45%)(5%暗く)。これで要素の背後に何があっても一貫した結果が得られます。

間違い3:異なるモニターで色をテストしない。MacBook Pro(P3色域、高輝度)で鮮やかに見える色が、安価なオフィスモニター(sRGB、低コントラスト)では色あせて見えるかもしれません。少なくとも1台のプレミアムでないディスプレイでテストしましょう。このテストを生き残る色が、ユーザーが実際に見る色です。

間違い4:ダークモードで色を無視する。単に色を反転したり白黒の背景を入れ替えたりすると、目に厳しいインターフェースになります。良いダークモードはやや彩度を落とした色(HSLでSを10-20%下げる)、微妙なグレーの違いで表面を持ち上げ(純粋な黒ではなく)、大きなテキスト領域のコントラストを下げます(純白on純黒は厳しすぎる——代わりに#e0e0e0 on #1a1a1aを使いましょう)。