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() を使用して色相を希望の量だけ回転します。色の補色を求めるには、半回転させます。この場合は、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 でカラーパレットを作成するをご覧ください。

モノクロパレット

モノクロのパレットを作成するには、同じ色相で明るさと暗さを変えたパレットを作成します。中央の色はパレットのソースカラーで、両側に 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))
  );
}