カラーパレットの構築における色あれこれ(前提編)
こんにちは。e-dashでプロダクトデザイナーをしているkazuです。
先日とある案件で「テナントごとに異なるテーマカラーを切り替えてUIを提供する」という要件があり、複数の色相をまたいでカラーパレットを管理する方法を検討しました。そこで得た内容をTIPSとしてまとめたいと思います。
※本記事は色の三属性(色相・明度・彩度)の基礎知識があることを想定して書いてます。
1. トークンは「Primitive」と「Semantic」に分けて管理するのが定石
案件により規模は大小あれど、色をデザインシステムで管理するのであれば、最終的に個々の色はデザイントークンとして開発者へ共有されます。
その際に、まず生の値(カラーコードなど)を「Primitive Color」として定義し、さらにその Primitive Color を用途ごとに「Semantic Color」として割り当てる形にすると、管理がしやすくなります。これは多くのデザインシステムで採用されており、デファクトスタンダードとなっている手法です。
-
Primitive Color: 基礎となる生の色の値。通常
#FFFFFF
といったカラーコードが紐付けられます。 -
Semantic Color: UI上での「意味」や「用途」に基づいて割り当てられた色。(例:
primary-button
)
なぜ管理しやすいのか?というと色やテーマの変更に強いメリットがあるからです。
-
Primitive Colorの参照先を変えたい場合
例えばblue-500
の色合いを少し明るくしたい場合、この定義を1箇所変更するだけでblue-500
を参照している全てのセマンティックカラーに自動で反映されます。 -
Semantic Colorの参照先を変えたい場合
ボタンに割り当てる色をblue-500
からblue-600
に変更したい場合も、セマンティックカラーの定義を1箇所変えるだけで、全てのプライマリーボタンに適用できます。
といった感じで、テーマ変更の際にも、同じSemantic Colorに対してテーマごとに異なるPrimitive Colorを割り当てるだけで完結できます。
FigmaではVariables
という機能でこれをGUI上で管理できます。Variablesを設定しておけば、FigmaからMCP(Manage Code Plugin)などを通じてコードを生成する際に、その参照先として活用できるのもメリットです。
2. 同じカラーコードでも色空間によって色の値が違う
お馴染みのRGBですが、その中でも種類があり、カバーできる色の範囲が異なることはご存知でしょうか。これは色空間(カラースペース)によるもので、色空間が違えば、同じRGB値でも表示される色が変わってしまうのです。
- sRGB: 1996年に国際電気標準会議(IEC)により定義。デバイスを選ばずに使える汎用性の高さが特徴。
- Display P3: 元々映画用のDCI-P3という広域な色空間をAppleが一般的なディスプレイ上で活用できるように作成したもの。高彩度の色がsRGBより得意で、グラデーションの表現がリッチになる。
-
Adobe RGB: 印刷物で使われるCMYKの表現領域を意識して設計されていて、写真や印刷の現場で使用される。
引用元(https://www.viewsonic.com/library/creative-work/using-dci-p3-color-gamut-for-video-editing/)
UIで用いるカラーは、クロスプラットフォーム対応を考慮すると、ほとんどの現場では実質sRGBがスタンダードになるかと思います。ただしiOS/macOSに特化したプロダクトであれば、Display P3の採用も視野に入れてよいでしょう(より鮮やかな色表現が可能)。[1]
また少し逸れますが、画像ファイルには「この画像はどの色空間で作られたか」を示すカラープロファイルが埋め込まれている場合があります。例えばAdobe RGBのプロファイルを持った画像をそのままsRGB環境で表示させると色がくすんで見えることがあります。そのため商品画像など、色の正確性が重視される現場では、プロファイルを意識したり、用途に合わせて正しい色空間に変換するといった工程が必要でしょう。
3. アクセシビリティにおけるカラーコントラストを押さえておく
テキストにおけるカラーコントラスト
アクセシビリティのガイドラインとなるWCAG2.2の達成基準「AA」では、テキストのカラーコントラスト比について以下のように定められています。
フォントの太さがbold未満の場合
- 17pt以下のテキスト : 4.5:1 以上
- 18pt以上のテキスト : 3:1 以上
フォントの太さがbold以上の場合
- 13pt以下のテキスト : 4.5:1 以上
- 14pt以上のテキスト : 3:1 以上
一方で、ロゴタイプや装飾目的のテキスト要素にはこの基準は適用されないことも頭の片隅に入れておくと良さそうです。
UIにおけるカラーコントラスト
ボタンやアイコンなど意味を持つUI要素とその隣接[2]する色との間に、3:1以上のコントラスト比が求められます。(達成基準1.4.11 非テキストのコントラスト)
4. 適切なカラーモデルを検討する
カラーモデルとは、色空間における色を数値で表現するために体系化されたルールのことです。[3] 代表的なカラーモデルを押さえておくとパレット作成がグッと捗ります。
-
HSB
Hue (色相)、Saturation (彩度)、Brightness (明度)で色をコントロールします。個別に色を選択する場面では、色の三属性と同じ感覚で扱えるため、デザイナーにとってはベストな選択肢です。一方で、システマチックに色を管理するには不向きです。 -
HSL
Hue (色相)、Saturation (彩度)、Luminance (輝度)で色をコントロールします。HSBと異なるのは「輝度(Luminance)」の概念で、50を基準として(純色)、数値が100に向かうにつれ白味が足され、0に向かうにつれて黒味が足されていきます。
これにより特定の色に対しての「明るい版」「暗い版」をシステマチックに作ることができます。
ただしLuminanceの値は人間が知覚的に感じる明るさと一致しない[4]という大きな欠点があり、異なる色相間でシステマチックにコントラスト比を揃えるには難易度が高いです。
下の画像は、HSLでの同輝度のステップでの黄色と青色の比較で、右側がグレースケールに置き換えたものになります。明らかにコントラスト比に差が出ているのがわかります。
-
LCH
Hue (色相)、 Chroma(彩度)、Lightness(明度)で色をコントロールします。大きな特徴としてはLightnessの数値と知覚的な明るさが一致することです。これによって、色相を変えたとしてもコントラスト比はある程度一定に保たれます。[5]
また、LCHはRGBより広範な人間の知覚に基づいたCIELABという色空間がベースになっています。
そのため選択する色がsRGBの色域外だったとき、変換(クリッピング)する必要があることは意識すべきです。
欠点としては、青系の色相において、彩度と明度の値だけ変えただけにもかかわらず、色相までが変わってしまう現象が発生することがあります。
ちなみに2023年の情報ですがMetaで採用されていたようです。Stripeの記事,Linearの記事)。
また、StripeやLinear(タスク管理ツール)もLCHを採用したという記事があります(-
OKLCH
LCHで前述した色相シフト問題を改良したカラーモデルです。CIELABを改良したOklabという色空間がベースになっています。
2020年に策定された新しいものですが、既にCSSでの記述も可能です(各ブラウザも対応済み)。[6]
OKLCHにおいては以下の記事が分かりやすかったです。
-
HCT
Googleのデザインシステム「Material Design3」で導入された新しいカラーモデルです。
色空間はHue(色相)とChroma(彩度)はCAM16、Tone(明度)はCIELABがベースになっており、Material Design3の特徴であるDynamic Color[7]の機能に特化しています。
色相を変えても知覚的な明るさが一致するという点では上記2つと同じですが、HCTはよりアクセシビリティ基準(WCAG)のコントラスト比が重視されています。
前提編はここまでです! 実践編では実際にカラーパレットを作成してみたいと思います。
-
過去に使用していたAdobeXDではカラーマネジメント機能は非対応だったため、mac上で表示される画面と実装で描画される色が一致せず苦戦しました。displayP3に慣れてしまうとsRGBが体感的に眠たい色に感じます。 ↩︎
-
用語の定義はそれぞれだと思いますが、ここでは色を数値で表現するためのルールや座標系を「カラーモデル」、そのルールで再現できる色の範囲 (Gamut)」を設定したものを「色空間」としています。 ↩︎
-
これは、人間の目が色によって感じる明るさが異なるから(スティーブンスのべき法則)。 ↩︎
-
CSS Colors 4仕様では、ブラウザは色域マッピングにOKLCH方式を使用することが推奨されています。しかしブラウザの自動色域マッピングは発展途上のため、OKLCHをCSSで指定する際はsrgbのフォールバックカラーの指定も行うことが望ましいとされています。出典元 ↩︎
Discussion