CSS とデザイントークンにおける HEX vs RGB vs HSL
デザインシステムで hex、rgb()、hsl() のどれを保存するか、alpha と丸めの相互作用、WCAG コントラストの位置づけを解説します。
同じブランドブルーは #2563EB、rgb(37, 99, 235)、hsl(221, 83%, 53%) として現れます。3 つとも正しくなり得ますが、丸め、alpha 合成、Figma でのデザイナー調整のあとにずれて離れることもあります。
この比較は、フロントエンドとデザインシステムエンジニアが 正規の保存形式 を選び、コントラストチェックを壊さずに他形式を導出する助けになります。
各形式が最適化するもの
| 形式 | 強み | 弱み |
|---|---|---|
| HEX | トークン、diff、引き渡しでコンパクト | 明るく/暗くするのを頭の中で計算しにくい |
| RGB | デザイン仕様書(0–255)と一致 | 冗長。色相関係が見えにくい |
| HSL | テーマ調整(同じ hue、新しい lightness) | 知覚的に均一ではない。コントラストの意外な結果 |
3 つのどれも「より正確」というわけではありません。OKLCH のような広い色空間に移らない限り、同じ sRGB トリプルの見方です。
トークンごとに 1 つの正(source of truth)を選ぶ
健全なデザインシステムは、意味トークン(--color-primary)ごとに 1 つの権威ある値 を保存し、プラットフォーム出力を生成します。
:root {
--color-primary: #2563eb;
--color-primary-hover: #1d4ed8;
--color-on-primary: #ffffff;
}
コンポーネントは散在する hex リテラルではなく --color-on-primary を参照します。マーケティングから更新されたスウォッチが来たら、トークンを 1 回更新し、ドキュメント用の派生 HSL/RGB を再ビルドします。
Color Converter で変換と WCAG コントラストを、白背景のスウォッチだけでなくテキストペアについても確認してください。
alpha 合成はコントラストを変える
白いカード上の rgba(37, 99, 235, 0.12) は、ソリッドブルー上の #2563EB テキストと同じペアではありません。WCAG チェックは、ユーザーが実際に見る表面で 合成後 の前景/背景を使う必要があります。
写真上の半透明オーバーレイは、フラット塗りより失敗しやすいです。Figma アートボードのデフォルトではなく、最悪の背景でテストしてください。
プログラム的パレットは HSL、配信は hex
よくあるパイプライン:
- デザイナーが Figma で作成(多くは hex または RGB)
- エンジニアがトークンに hex を保存
- ビルドスクリプトがテーマジェネレーターや chart API 用に HSL を出力
- メール/PDF エクスポートは
hsl()サポートが不安定なため インライン hex
HSL lightness を引いて hover 状態を生成する場合、新しいペアでコントラストを再実行してください。「10% 暗く」が AA を保証するわけではありません。
丸めと往復ドリフト
HEX → HSL → HEX は同一バイトに戻らないことがあります。次の場合に重要です。
- CSS バンドルの CI スナップショット比較
- Android XML カラーと web トークンの同期
トークンリポジトリの README に丸めルールを文書化してください。アプリごとに独立して丸めないでください。
クイック判断ガイド
- コンパクトな git diff と汎用ツールサポートが必要? → 正規形式は hex
- canvas/WebGL/chart API と連携? → ビルド時に RGB を導出
- 1 つの hue ランプから light/dark テーマ? → HSL または OKLCH で調整を記述し、各ステップ後にコントラストを確認
- HTML メールを配信? → テンプレートは hex のみ
関連学習
WCAG 比率、CSS Color Level 4 構文、サンプリングワークフローは Color for Developers course を参照してください。
まとめ
HEX、RGB、HSL は競合する教義ではなく、交換可能な見方です。 1 つの正規形式を選び、残りを意図的に導出し、実際の背景でコントラストを計測してください。それが #2563EB を本番で 1 つの青に保つ方法です。