CSS 相対色構文

別の色のチャネルと値に基づいて新しい色を作成します。

Adam Argyle
Adam Argyle

Chrome 119 では、CSS Color Level 5 の非常に強力な色機能が導入されています。相対カラーの構文を使用すると、CSS 内での色操作がスムーズになり、作成者やデザイナーは次のことができるようになります。

相対色構文のは、色の不透明度を変更するには、色のチャネル(通常は HSL)のカスタム プロパティを作成し、最終的な色と最終的なバリアント色に組み立てる必要がありました。これは、多くの色を管理することを意味し、すぐに手間がかかります。

:root {
  --brand-hue: 300deg;
  --brand-saturation: 75%;
  --brand-lightness: 50%;

  --brand-hsl:
    var(--brand-hue)
    var(--brand-saturation)
    var(--brand-lightness);

  --brand-color: hsl(var(--brand-hsl));

  /* all this work just so I can set the opacity to 50% in a variant */
  --brand-color-variant: hsl(var(--brand-hsl) / 50%);
}

相対色構文を使用すると、必要な色空間や構文でブランドカラーを作成でき、コードを大幅に減らして半透明のバリエーションを作成できます。また、スタイルとシステムの意図を読み取ることもはるかに簡単になります。

:root {
  --brand-color: hsl(300deg 75% 50%);
  --brand-color-variant: hsl(from var(--brand-color) h s l / 50%);
}

この記事では、構文について学び一般的な色の操作を紹介します

動画の方がよい場合は、この記事のほとんどがこの GUI チャレンジで説明されています。

構文の概要

相対色構文の目的は、別の色から色を導き出すことにあります。ベースカラーは元の色と呼ばれ、新しい from キーワードの後に続く色です。ブラウザは、この元の色を変換して分解し、新しい色の定義で使用する変数として各パーツを提供します。

構文 rgb(緑色の r g b / アルファから)の図が表示されます。矢印が緑色の上部から出て、関数の rgb の開始部分にアーチ状に伸びています。この矢印は 4 つの矢印に分割され、関連する変数を指しています。4 つの矢印は、赤、緑、青、アルファです。赤と青の値は 0、緑は 128、アルファは 100% です。

上の図は、元の色 green が新しい色の色空間に変換され、rgbalpha 変数として表される個々の数値に変換され、新しい rgb() 色の値として直接使用されることを示しています。

この画像は内訳、プロセス、変数を示していますが、色は変わりません。変数は変更されていない状態で色に戻されるため、緑色のままになります。

from キーワード

学習する構文の最初の部分は、色を指定する from <color> の部分です。値を指定する直前に記述します。次のコード例では、rgb() の値を指定する直前に from green のみが追加されています。

.syntax-introduction_same-colors {
  color: green;
  color: rgb(0 128 0);
  color: rgb(from green r g b);    /* result = rgb(0 128 0) */
}

この from キーワードは、関数表記の最初のパラメータとして使用すると、色の定義を相対色に変換します。from キーワードの後に、CSS は色を想定しています。これは、次の色のヒントとなる色です。

色変換

簡単に言うと、緑を r g と b のチャネルに変換して、新しい色で使用します。

rgb(from green r g b)           /* r=0 g=128 b=0 */
rgb(from rgb(0 128 0) r g b);   /* r=0 g=128 b=0 */

カスタム プロパティの色

rgb from green はとても明確で理解しやすいです。カスタム プロパティと相対色構文が非常に適しているのは、from 色の謎を解くことができるためです。また、任意の形式で新しい色を作成するため、通常はカスタム プロパティの色の色形式を把握する必要はありません。

rgb(from rgb(255 105 180) r g b) /* ????? */
rgb(from var(--hotpink) r g b)   /* clear */

好みの色空間で作業する

色空間は、機能的な色表記を使って選択できます。

rgb(from hsl(120 100% 25%) r g b)     /*  r=0   g=128  b=0    */
hsl(from hsl(120 100% 25%) h s l)     /*  h=120 s=100% l=25%  */
hwb(from hsl(120 100% 25%) h w b)     /*  h=120 w=0%   b=50%  */
lch(from hsl(120 100% 25%) l c h)     /*  l=46  c=68   h=134  */

相対色の構文には、その変換ステップがあります。from の後の色は、相対色の先頭で指定された色空間に変換されます。入力と出力は一致する必要がないため、自由度が高くなります。

色空間を選択できる機能も便利です。色空間を選択する場合は、設定よりも色の切り替えの種類に重点を置く傾向があるためです。設定は、カラー形式やチャンネルの種類ではなく、結果に適用されます。ユースケースを示すセクションでは、この点がより明確になります。異なる色空間は、異なるタスクに適しています。

変数を組み合わせ、一致させ、省略、繰り返す

この構文にはおかしな点がありますが、変数を順番に戻す必要はなく、繰り返し使用できます。

rgb(from green g g g)    /* rgb(128 128 128) */
rgb(from green b r g)    /* rgb(0 0 128) */
rgb(from green 0 0 g)    /* rgb(0 0 128) */

不透明度を変数として使用

この構文では、不透明度も alpha という名前の変数として指定します。これは省略可能で、機能色表記の / の後に記述します。

rgb(from #00800080 r g b / alpha)             /* alpha=50% */
rgb(from rgba(0,128,0,.5) r g b / alpha)      /* alpha=50% */
rgb(from rgb(0 128 0 / 50%) r g b / alpha)    /* alpha=50% */

変数に calc() などの CSS 関数を使用する

ここまでは、緑色を何度も作成してきました。構文を学び、変換と構造解析のステップを理解する。ここで、変数を変更し、入力と異なるように出力を変更します。

green                              /*  h=120 s=100% l=25%  */
hsl(from green calc(h * 2) s l)    /*  h=240 s=100% l=25%  */

ネイビーになりました。色相が 2 倍になり、120 の色相が 240 に変わり、色が完全に変化しました。これにより、色相がカラーホイール上で回転します。これは、HSLHWBLCHOKLCH などの円筒形の色空間で非常に簡単にできる便利なトリックです。

チャンネルの値を視覚的に確認して、推測したり仕様を覚えたりせずに正しい計算を行うには、こちらの相対色構文のチャンネル値ツールをお試しください。指定した構文に基づいて各チャンネルの値が表示されるため、使用可能な値を正確に把握できます。

ブラウザのサポートを確認する

@supports (color: rgb(from white r g b)) {
  /* safe to use relative color syntax */
}

ユースケースとデモ

次の例とユースケースには、同様または同じ結果を得るためのさまざまな代替構文があります。バリエーションは、色空間と提供するチャネルによって異なります。

また、多くの例では、byto という表現で色調整を示しています。色の変更 by は相対的な色の変化です。これは変数の値を使用して、現在の値に基づいて調整を行う変更です。色の変更 to は、絶対色の変更です。つまり、変数の値を使用せず、まったく新しい値を指定する変更です。

すべてのデモは、こちらの Codepen コレクションで確認できます。

色を明るくする

OKLCH、OKLABXYZsRGB 色空間は、明るさを落とす際の予測しやすい色空間を提供します。

明るさを調整する

次の例 .lighten-by-25 では、色 blue を OKLCH に変換し、現在の値に 1.25 を乗算して l(明るさ)チャネルを増やして青を明るくします。これにより、青色の明るさが 25% 白色に押し下げられます。

.lighten-by-25 {
  background: oklch(from blue calc(l * 1.25) c h);
}

特定の値まで明るくする

次の例の .lighten-to-75 は、l チャネルを使用して blue を明るくせず、代わりに値を 75% に完全に置き換えます。

.lighten-to-75 {
  background: oklch(from blue 75% c h);
}

色を暗くする

色を明るくするのに効果的な色空間は、色を暗くするのにも効果的です。

暗くする量

次の例の .darken-by-25 は、青色を OKLCH に変換し、値に .75 を乗算して l(明度)チャネルを 25% 減らして青色を暗くします。これにより、青色が黒色に 25% 近づきます。

.darken-by-25 {
  background: oklch(from blue calc(l * .75) c h);
}

指定した値まで暗くする

次の例の .darken-to-25 は、l チャネルを使用して blue を暗くせず、代わりに値を 25% に完全に置き換えます。

.darken-to-25 {
  background: oklch(from blue 25% c h);
}

色の彩度を上げる

一定の値で飽和させる

次の例の .saturate-by-50 は、hsl()s を使用して、orchid の鮮やかさを相対 50% で増やします。

.saturate-by-50 {
  background: hsl(from orchid h calc(s * 1.5) l);
}

特定の量まで飽和させる

次の .saturate-to-100 の例では、hsl()s チャネルを使用せず、目的の飽和値を指定しています。この例では、飽和度は 100% に引き上げられています。

.saturate-to-100 {
  background: hsl(from orchid h 100% l);
}

色の彩度を下げる

彩度を減らす

次の例 .desaturate-by-half では、hsl()s を使用して indigo の彩度を半分に減らしています。

.desaturate-by-half {
  background: hsl(from indigo h calc(s / 2) l);
}

特定の値にデシタレーションする

特定の値にデシタレーションすることもできます。次の例の .desaturate-to-25 は、indigo に基づいて新しい色を作成しますが、彩度を 25% に設定します。

.desaturate-to-25 {
  background: hsl(from indigo h 25% l);
}

色彩度をブーストする

この効果は色の彩度を上げる効果に似ていますが、いくつかの点で異なります。まず、これは saturation の変更ではなく chroma の変更です。これは、ハイダイナミック レンジにブーストできる色空間では彩度が使用されないためです。chroma を備えた色空間はハイ ダイナミック レンジに対応しているため、作成者は彩度よりもさらに色の鮮やかさを向上させることができます。

.increase-chroma {
  background: oklch(from orange l calc(c + .1) h);
}

色の不透明度を調整する

色の半透明バリエーションを作成することは、デザインシステムで最も一般的な色調整の 1 つです。まだ確認していない場合は、この記事の冒頭の例をご覧ください。問題領域を明確に示しています。

不透明度を数値で調整する

.decrease-opacity-by-25 {
  background: rgb(from lime r g b / calc(alpha / 2));
}

不透明度を指定した値に調整する

.decrease-opacity-to-25 {
  background: rgb(from lime r g b / 25%);
}

色を反転する

色反転は、カラー ライブラリにある一般的な色調整関数です。これを行う 1 つの方法は、色を RGB に変換してから、各チャネルの値を 1 から減算することです。

.invert-each-rgb-channel {
  background: rgb(from yellow calc(255 - r) calc(255 - g) calc(255 - b));
}

補色

色を反転させるのではなく、補色にしたい場合は、色相の回転が適しています。色相を角度として提供する色空間を選択し、calc() を使用して色相を任意の量だけ回転します。色の補数を求めるには、0.5 回転だけ回転します。この場合、h チャンネルに対して 180 を加算または減算すると計算結果になります。

.complementary-color {
  background: hsl(from blue calc(h + 180) s l);
}

色のコントラストを調整する

アクセシビリティを確保した配色コントラスト比率を達成する方法として、L&midast;(Lstar)を検討してください。これは、LCH と OKLCH の(ほぼ)知覚的に均一な明度(L)チャネルを calc() で使用します。低コントラスト、中コントラスト、高コントラストのいずれをターゲットとするかに応じて、L&middot; のデルタは約 40、約 50、約 60 になります。

この手法は、LCH または OKLCH の任意の色相で効果的です。

暗い色とのコントラスト

.well-contrasting-darker-color クラスは、デルタ 60 の L* を示します。元の色が暗い色(明るさの値が低い)であるため、明るさチャンネルに 60%(.6)が追加されます。この手法は、明るい背景にコントラストがよく、同じ色相の暗いテキスト色を見つけるために使用されます。

.well-contrasting-darker-color {
  background: darkred;
  color: oklch(from darkred calc(l + .60) c h);
}

明るい色にコントラストをつける

.well-contrasting-lighter-color クラスは、デルタが 60% の L* を示しています。元の色は明るい色(明るさの値が高い)であるため、明るさチャンネルから .60 が減算されます。

.well-contrasting-lighter-color {
  background: lightpink;
  color: oklch(from lightpink calc(l - .60) c h);
}

カラー パレット

相対色の構文は、カラーパレットの作成に非常に適しています。多数の色空間を使用できるため、特に便利で強力です。以下の例ではすべて OKLCH を使用しています。明度チャネルは信頼性が高く、色相チャネルは副作用なしで回転できるためです。最後の例では、明度と色相の回転の調整を組み合わせて、より興味深い結果を生み出しています。

これらのサンプルのソースコードを開き、--base-color を変更して、これらのパレットがどれほど動的であるかを確認してみてください。楽しいですよ。

動画が気に入ったら、OKLCH を使用して CSS でカラーパレットを作成する方法を YouTube で詳しく解説しています

モノクロのパレット

モノクロパレットを作成するには、同じ色相で明るさと暗さを変えたパレットを作成します。中央の色はパレットのソースカラーで、左右に 2 つの明るいバリエーションと 2 つの暗いバリエーションがあります。

:root {
  --base-color: deeppink;

  --color-0: oklch(from var(--base-color) calc(l + .20) c h); /* lightest */
  --color-1: oklch(from var(--base-color) calc(l + .10) c h);
  --color-2: var(--base-color);
  --color-3: oklch(from var(--base-color) calc(l - .10) c h);
  --color-4: oklch(from var(--base-color) calc(l - .20) c h); /* darkest */
}
相対色構文と OKLCH で作成されたさまざまなパレットを試す

無料の CSS 変数のライブラリである Open Props には、この戦略で構築されたカラーパレットが用意されており、インポートで簡単に使用できます。また、すべてカスタマイズ可能な色から作成されているため、色を指定するだけでパレットが生成されます。

類似パレット

OKLCH と HSL では色相の回転が非常に簡単であるため、類似色パレットを簡単に作成できます。好みの程度で色相を回転し、ベースカラーを変更すると、新しいパレットがブラウザで作成されるのを確認できます。

:root {
  --base-color: blue;

  --primary:   var(--base-color);
  --secondary: oklch(from var(--base-color) l c calc(h - 45));
  --tertiary:  oklch(from var(--base-color) l c calc(h + 45));
}

三原色パレット

補色と同様に、3 色配色は、ベースカラーに対して反対の色相を回転させた、調和のとれた配色です。補色がカラーホイールの中央に引かれた直線のように反対側にある場合、トライアディック パレットは三角形の線のように、ベースカラーから 2 色を均等に回転させます。これを行うには、色相 120deg を回転します。

これは色彩理論を少し簡素化したものですが、興味がある場合は、より複雑な三原色パレットの作成を始めるのに十分です。

:root {
  --base-color: yellow;
  --triad-1: oklch(from var(--base-color) l c calc(h - 120));
  --triad-2: oklch(from var(--base-color) l c calc(h + 120));
}

四色パレット

四色パレットは、色相環の周囲に均等に分割された 4 色で構成され、明確な優先値のないパレットになります。2 組の補色のようにも考えることができます。適切に使用すれば、非常に意味のあるものになる可能性があります。

これは色理論をやや単純化したものですが、より複雑な四辺形のパレットに興味があるならこれで十分です。

:root {
  --base-color: lime;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) l c calc(h + 90));
  --color-3: oklch(from var(--base-color) l c calc(h + 180));
  --color-4: oklch(from var(--base-color) l c calc(h + 270));
}

わずかに回転するモノクロ

多くのカラー エキスパートがこのテクニックを活用しています。ただし、モノクロのカラースケールは非常に退屈なものになる可能性があります。解決策は、明るさが変更されるたびに、新しい色に微調整または大調整の色相回転を追加することです。

次の例では、各スウォッチの明るさを 10% 減らし、色相を 10 度回転させています。その結果、ホットピンクから藍色のパレットが、グラデーションのようにシームレスに溶け込んでいます。

:root {
  --base-color: deeppink;

  --color-1: var(--base-color);
  --color-2: oklch(from var(--base-color) calc(l - .10) c calc(h - 10));
  --color-3: oklch(from var(--base-color) calc(l - .20) c calc(h - 20));
  --color-4: oklch(from var(--base-color) calc(l - .30) c calc(h - 30));
  --color-5: oklch(from var(--base-color) calc(l - .40) c calc(h - 40));
}
OKLCH と色相の回転で作成されたこのリーダーボードをお試しください

次のリーダーボード インターフェースでは、この色相のローテーション戦略が使用されています。各リストアイテムは、ドキュメント内のインデックスを --i という変数として追跡します。このインデックスは、色相、明度、色調の調整に使用されます。調整は 5% または 5 度のみで、上記の deeppink の例よりもはるかに微妙です。そのため、このリーダーボードがこれほどエレガントにどの色合いにもできる理由に気づくには、鋭い目が必要です。

リーダーボードの下にあるスライダーの色相を必ず変更してください。相対カラー構文を使用すると、美しい色の瞬間を作成できます。

li {
  --_bg: oklch(
    /* decrease lightness as list grows */
    calc(75% - (var(--i) * 5%))

    /* decrease chroma as list grows */
    calc(.2 - (var(--i) * .01))

    /* lightly rotate the hue as the list grows */
    calc(var(--hue) - (var(--i) + 5))
  );
}