使用相對顏色

CSS 顏色模組定義了相對顏色語法,它允許一個 CSS <color> 值相對於另一個顏色進行定義。這是一個強大的功能,可以輕鬆地為現有顏色建立補充色——例如更亮、更暗、更飽和、半透明或反色的變體——從而實現更有效的調色盤建立。

本文將解釋相對顏色語法,展示不同的選項,並看一些說明性的例子。

通用語法

一個相對 CSS 顏色值具有以下通用語法結構

css
color-function(from origin-color channel1 channel2 channel3)
color-function(from origin-color channel1 channel2 channel3 / alpha)

/* color space included in the case of color() functions */
color(from origin-color colorspace channel1 channel2 channel3)
color(from origin-color colorspace channel1 channel2 channel3 / alpha)

相對顏色使用與絕對顏色相同的顏色函式建立,但引數不同

  1. 包含一個基本的顏色函式(由上面的 color-function() 表示),例如 rgb()hsl() 等。選擇哪個函式取決於你想要為正在建立的相對顏色(輸出顏色)使用的顏色模型。
  2. 傳入相對顏色所基於的源顏色(由上面的 origin-color 表示),並以 from 關鍵字為字首。這可以是任何有效的 <color> 值,使用任何可用的顏色模型,包括包含在 CSS 自定義屬性中的顏色值、系統顏色、currentColor,甚至是另一個相對顏色。
  3. 對於 color() 函式,需要包含輸出顏色的colorspace
  4. 為每個單獨的通道提供一個輸出值。輸出顏色在源顏色之後定義——由上面的 channel1channel2channel3 佔位符表示。這裡定義的通道取決於你用於相對顏色的顏色函式。例如,如果你使用 hsl(),你需要定義色相、飽和度和亮度的值。每個通道值可以是一個新值、與原始值相同的值,或相對於源顏色通道值的值。
  5. 可選地,可以為輸出顏色定義一個型別為 <alpha-value>alpha 通道值,並以斜槓(/)為字首。如果未明確指定 alpha 通道值,則它預設為 origin-color 的 alpha 通道值(而不是 100%,絕對顏色值是這種情況)。

瀏覽器將源顏色轉換為與顏色函式相容的語法,然後將其解構為分量顏色通道(如果源顏色有 alpha 通道,則還包括 alpha 通道)。這些分量在顏色函式內部作為適當命名的值可用——對於 rgb() 函式是 rgbalpha,對於 lab() 函式是 labalpha,對於 hwb() 函式是 hwbalpha 等——可以用來計算新的輸出通道值。

讓我們來看看相對顏色語法的實際應用。下面的 CSS 用於樣式化兩個 <div> 元素,一個具有絕對背景顏色——red——另一個具有使用 rgb() 函式建立的相對背景顏色,同樣基於 red 顏色值

css
#one {
  background-color: red;
}

#two {
  background-color: rgb(from red 200 g b / alpha);
}

輸出如下:

相對顏色使用 rgb() 函式,它以 red 作為源顏色,將其轉換為等效的 rgb() 顏色(rgb(255 0 0)),然後定義新顏色的紅色通道值為 200,綠色、藍色和 alpha 通道的值與源顏色相同(它使用了瀏覽器在函式內部提供的 gb 值,它們都等於 0,而 alpha100%)。

這導致輸出為 rgb(200 0 0)——一個稍暗的紅色。如果我們指定紅色通道值為 255(或直接使用 r 值),則最終的輸出顏色將與輸入值完全相同。瀏覽器的最終輸出顏色(計算值)是等效於 rgb(200 0 0) 的 sRGB color() 值——color(srgb 0.784314 0 0)

備註: 如上所述,當計算相對顏色時,瀏覽器做的第一件事是將提供的源顏色(在上面的例子中是 red)轉換為與所用顏色函式相容的值(在這種情況下是 rgb())。這樣做是為了讓瀏覽器能夠從源顏色計算出輸出顏色。雖然計算是相對於所用顏色函式進行的,但實際的輸出顏色值取決於顏色的色彩空間

  • 較舊的 sRGB 顏色函式無法表示可見顏色的全部光譜。(hsl()hwb()rgb())的輸出顏色被序列化為 color(srgb) 以避免這些限制。這意味著透過 HTMLElement.style 屬性或 CSSStyleDeclaration.getPropertyValue() 方法查詢輸出顏色值時,會返回一個 color(srgb ...) 值。
  • 對於較新的顏色函式(lab()oklab()lch()oklch()),相對顏色的輸出值使用與所用顏色函式相同的語法表示。例如,如果正在使用 lab() 顏色函式,則輸出顏色將是一個 lab() 值。

以下所有行都產生等效的輸出顏色

css
red
rgb(255 0 0)
rgb(from red 255 0 0)
rgb(from red 255 0 0 / 1)
rgb(from red 255 0 0 / 100%)

rgb(from red 255 g b)
rgb(from red r 0 0)
rgb(from red r g b / 1)
rgb(from red r g b / 100%)

rgb(from red r g b)
rgb(from red r g b / alpha)

/* With `red`, the g and b are the same, making them interchangeable */
rgb(from red r g g)
rgb(from red r b b)
rgb(from red 255 g g)
rgb(from red 255 b b)

語法靈活性

在函式中可用的解構源顏色通道值與開發者設定的輸出顏色通道值之間有一個重要的區別。

重申一下,當定義一個相對顏色時,源顏色的通道值在函式中可用,用於定義輸出顏色的通道值。下面的例子使用 rgb() 函式定義一個相對顏色,並使用源顏色通道值(作為 rgb 可用)作為輸出通道值,這意味著輸出顏色與源顏色相同

css
rgb(from red r g b)

然而,在指定輸出值時,你完全不需要使用源顏色的通道值。你需要以正確的順序提供輸出通道值(例如,對於 rgb(),是紅色、然後綠色、然後藍色),但它們可以是任何你希望的值,只要它們是這些通道的有效值即可。這賦予了相對 CSS 顏色高度的靈活性。

例如,如果你願意,你可以指定如下所示的絕對值,將 red 轉換為 blue

css
rgb(from red 0 0 255)
/* output color is equivalent to rgb(0 0 255), full blue */

備註: 如果你正在使用相對顏色語法,但輸出與源顏色相同的顏色或一個完全不基於源顏色的顏色,那麼你實際上並沒有在建立相對顏色。你不太可能在真實的程式碼庫中這樣做,而是可能會直接使用絕對顏色值。但是,我們認為解釋你可以用相對顏色語法做到這一點是有用的,作為學習它的起點。

你甚至可以混合或重複提供的值。下面這個例子輸入一個稍暗的紅色,輸出一個淺灰色——輸出顏色的 rgb 通道都設定為源顏色的 r 通道值

css
rgb(from rgb(200 0 0) r r r)
/* output color is equivalent to rgb(200 200 200), light gray */

以下示例使用源顏色的通道值作為輸出顏色的 rgb 通道值,但順序相反

css
rgb(from rgb(200 170 0) b g r)
/* output color is equivalent to rgb(0 170 200) */

支援相對顏色的顏色函式

在上一節中,我們只看到了透過 rgb() 函式定義的相對顏色。然而,相對顏色可以使用任何現代 CSS 顏色函式來定義——color()hsl()hwb()lab()lch()oklab()oklch()rgb()。每種情況下的通用語法結構都是相同的,儘管源顏色值有適合所用函式的不同名稱。

下面你可以找到每個顏色函式的相對顏色語法示例。每種情況都是最簡單的可能,輸出顏色通道值與源顏色通道值完全匹配

css
/* color() with and without alpha channel */
color(from red a98-rgb r g b)
color(from red a98-rgb r g b / alpha)

color(from red xyz-d50 x y z)
color(from red xyz-d50 x y z / alpha)

/* hsl() with and without alpha channel */
hsl(from red h s l)
hsl(from red h s l / alpha)

/* hwb() with and without alpha channel */
hwb(from red h w b)
hwb(from red h w b / alpha)

/* lab() with and without alpha channel */
lab(from red l a b)
lab(from red l a b / alpha)

/* lch() with and without alpha channel */
lch(from red l c h)
lch(from red l c h / alpha)

/* oklab() with and without alpha channel */
oklab(from red l a b)
oklab(from red l a b / alpha)

/* oklch() with and without alpha channel */
oklch(from red l c h)
oklch(from red l c h / alpha)

/* rgb() with and without alpha channel */
rgb(from red r g b)
rgb(from red r g b / alpha)

值得再次提及的是,源顏色的顏色系統不需要與用於建立輸出顏色的顏色系統匹配。這再次提供了很大的靈活性。通常,你不會對源顏色定義的系統感興趣,甚至可能不知道它是什麼(你可能只是有一個自定義屬性值需要操作)。你只想輸入一個顏色,例如,透過將其放入 hsl() 函式並改變亮度值來建立它的一個更亮的變體。

使用自定義屬性

在建立相對顏色時,你可以使用CSS 自定義屬性中定義的值,既可用於源顏色,也可用於輸出顏色通道值的定義中。讓我們來看一個例子。

在下面的 CSS 中,我們定義了兩個自定義屬性

  • --base-color 包含我們的基礎品牌顏色——purple。這裡我們使用了一個命名顏色關鍵字,但相對顏色可以接受任何顏色語法作為源顏色。
  • --standard-opacity 包含了我們想要應用於半透明盒子的標準品牌不透明度值——0.75

然後我們給兩個 <div> 元素設定了背景顏色。一個被賦予了絕對顏色——我們的 --base-color 品牌紫色。另一個被賦予了相對顏色,等於我們的品牌紫色,但經過轉換以新增一個等於我們標準不透明度值的 alpha 通道。

css
:root {
  --base-color: purple;
  --standard-opacity: 0.75;
}

#one {
  background-color: var(--base-color);
}

#two {
  background-color: hwb(from var(--base-color) h w b / var(--standard-opacity));
}

輸出如下:

使用數學函式

你可以使用 CSS 數學函式,如 calc(),來計算輸出顏色通道的值。讓我們來看一個例子。

下面的 CSS 用於為三個 <div> 元素設定不同的背景顏色。中間的元素被賦予了未經修改的 --base-color,而左右兩邊的元素則被賦予了該 --base-color 的更亮和更暗的變體。這些變體是使用相對顏色定義的——將 --base-color 傳遞給一個 lch() 函式,然後透過 calc() 函式修改其亮度通道以達到所需效果。更亮的顏色在亮度通道上增加了 20%,更暗的顏色則減少了 20%。

css
:root {
  --base-color: orange;
}

#one {
  background-color: lch(from var(--base-color) calc(l + 20) c h);
}

#two {
  background-color: var(--base-color);
}

#three {
  background-color: lch(from var(--base-color) calc(l - 20) c h);
}

輸出如下:

操縱 alpha 通道

這個例子演示瞭如何改變一個命名顏色的 alpha 通道。這裡,我們有一個被容器包裹的項,它們都具有 teal 的背景色。為了區分這兩個背景,我們使用相對顏色特性、calc() 函式和一個自定義屬性來改變 alpha 通道的值。

html
<div class="container">
  <div class="item"></div>
</div>
css
div {
  background-color: rgb(
    from teal r g b / calc(alpha * var(--alpha-multiplier))
  );
}

.container {
  --alpha-multiplier: 0.3;
}

.item {
  --alpha-multiplier: 1;
}

alpha 通道使用 alpha 關鍵字引用。在這種情況下,calc(alpha * var(--alpha-multiplier)) 表示式透過將 alpha--alpha-multiplier 自定義屬性值相乘來修改 alpha 通道的值。由於乘數 0.3 小於 1.0,容器獲得了半透明的背景。

輸出如下:

通道值解析為 <number>

為了使通道值計算在相對顏色中起作用,所有源顏色通道值都會解析為適當的 <number> 值。例如,在上面的 lch() 示例中,我們透過在源顏色的 l 通道值上加減數字來計算新的亮度值。如果我們嘗試執行 calc(l + 20%),將會導致無效的顏色——l 是一個 <number>,不能與 <percentage> 相加。

  • 最初指定為 <percentage> 的通道值會解析為適合輸出顏色函式的 <number>
  • 最初指定為 <hue> 角度的通道值會解析為一個在 0360(含)範圍內的度數。

請檢視不同的顏色函式頁面,瞭解它們的源通道值具體會解析成什麼。

檢查瀏覽器支援

你可以透過在 @supports at-rule 中執行它來檢查瀏覽器是否支援相對顏色語法。

例如

css
@supports (color: hsl(from white h s l)) {
  /* safe to use hsl() relative color syntax */
}

示例

備註: 你可以在不同函式表示法的專用頁面上找到更多演示相對顏色語法用法的示例:color()hsl()hwb()lab()lch()oklab()oklch()rgb()

調色盤生成器

此示例允許你選擇一個基礎顏色和一種調色盤型別。然後瀏覽器將根據所選的基礎顏色顯示一個相應的調色盤。調色盤的選擇如下

  • 互補色:包括兩種在色輪上處於相對位置的顏色,或者換句話說,是相反的色相(有關色相和色輪的更多資訊,請參閱 <hue> 資料型別)。這兩種顏色被定義為一種基礎顏色,以及基礎顏色色相通道 +180 度的顏色。
  • 三色組:包括三種在色輪上等距分佈的顏色。這三種顏色被定義為一種基礎顏色、基礎顏色色相通道 -120 度的顏色,以及基礎顏色色相通道 +120 度的顏色。
  • 四色組:包括四種在色輪上等距分佈的顏色。這四種顏色被定義為一種基礎顏色,以及基礎顏色色相通道 +90、+180 和 +270 度的顏色。
  • 單色:包括多種具有相同色相但亮度值不同的顏色。在我們的示例中,我們在單色調色盤中定義了五種顏色——基礎顏色,以及基礎顏色亮度通道 -20、-10、+10 和 +20 的顏色。

HTML

下面附上完整的 HTML 以供參考。其中最有趣的部分如下

  • --base-color 自定義屬性作為內聯 style 儲存在 ID 為 container<div> 元素上。我們把它放在這裡是為了方便使用 JavaScript 更新其值。我們提供了一個初始值 #ff0000 (red),以便在示例載入時顯示基於該值的調色盤。請注意,通常我們可能會在 <html> 元素上設定它,但 MDN 的即時示例在渲染時會移除它。
  • 基礎顏色選擇器是使用一個 <input type="color"> 控制元件建立的。當在此控制元件中設定新值時,--base-color 自定義屬性會透過 JavaScript 設定為該值,從而生成一個新的調色盤。所有顯示的顏色都是基於 --base-color 的相對顏色。
  • 一組 <input type="radio"> 控制元件用於選擇要生成的調色盤型別。當在這裡選擇一個新值時,JavaScript 會用於在 container <div> 上設定一個新的類來表示所選的調色盤。在 CSS 中,使用後代選擇器來定位子 <div>(例如,.comp :nth-child(1)),以便為它們應用正確的顏色並隱藏未使用的 <div> 節點。
  • container <div> 包含了顯示生成的調色盤顏色的子 <div>。請注意,它上面設定了一個初始類 comp,以便頁面首次載入時顯示一個互補色方案。
html
<div>
  <h1>Color palette generator</h1>
  <form>
    <div id="color-picker">
      <label for="color">Select a base color:</label>
      <input type="color" id="color" name="color" value="#ff0000" />
    </div>
    <div>
      <fieldset>
        <legend>Select a color palette type:</legend>

        <div>
          <input
            type="radio"
            id="comp"
            name="palette-type"
            value="comp"
            checked />
          <label for="comp">Complementary</label>
        </div>

        <div>
          <input
            type="radio"
            id="triadic"
            name="palette-type"
            value="triadic" />
          <label for="triadic">Triadic</label>
        </div>

        <div>
          <input
            type="radio"
            id="tetradic"
            name="palette-type"
            value="tetradic" />
          <label for="tetradic">Tetradic</label>
        </div>

        <div>
          <input
            type="radio"
            id="monochrome"
            name="palette-type"
            value="monochrome" />
          <label for="monochrome">Monochrome</label>
        </div>
      </fieldset>
    </div>
  </form>
  <div id="container" class="comp">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </div>
</div>

CSS

下面我們只展示了設定調色盤顏色的 CSS。請注意,在每種情況下,如何使用後代選擇器為所選調色盤的每個子 <div> 應用正確的 background-color。我們更關心 <div> 在源順序中的位置而不是元素的型別,所以我們使用了 :nth-child 來定位它們。

在最後一條規則中,我們使用了通用兄弟選擇器 (~) 來定位每種調色盤型別中未使用的 <div> 元素,透過設定 display: none 來阻止它們被渲染。

這些顏色包括 --base-color,以及從該 --base-color 派生的相對顏色。相對顏色使用 lch() 函式——傳入源 --base-color 並定義一個輸出顏色,其亮度或色相通道根據需要進行了調整。

css
/* Complementary colors */
/* Base color, and base color with hue channel +180 degrees */

.comp :nth-child(1) {
  background-color: var(--base-color);
}

.comp :nth-child(2) {
  background-color: lch(from var(--base-color) l c calc(h + 180));
}

/* Use @supports to add in support old syntax that requires deg units
   to be specified in hue calculations. This is required for Safari 16.4+. */
@supports (color: lch(from red l c calc(h + 180deg))) {
  .comp :nth-child(2) {
    background-color: lch(from var(--base-color) l c calc(h + 180deg));
  }
}

/* Triadic colors */
/* Base color, base color with hue channel -120 degrees, and base color */
/* with hue channel +120 degrees */

.triadic :nth-child(1) {
  background-color: var(--base-color);
}

.triadic :nth-child(2) {
  background-color: lch(from var(--base-color) l c calc(h - 120));
}

.triadic :nth-child(3) {
  background-color: lch(from var(--base-color) l c calc(h + 120));
}

/* Use @supports to add in support old syntax that requires deg units
   to be specified in hue calculations. This is required for Safari 16.4+. */
@supports (color: lch(from red l c calc(h + 120deg))) {
  .triadic :nth-child(2) {
    background-color: lch(from var(--base-color) l c calc(h - 120deg));
  }

  .triadic :nth-child(3) {
    background-color: lch(from var(--base-color) l c calc(h + 120deg));
  }
}

/* Tetradic colors */
/* Base color, and base color with hue channel +90, +180, and +270 degrees */

.tetradic :nth-child(1) {
  background-color: var(--base-color);
}

.tetradic :nth-child(2) {
  background-color: lch(from var(--base-color) l c calc(h + 90));
}

.tetradic :nth-child(3) {
  background-color: lch(from var(--base-color) l c calc(h + 180));
}

.tetradic :nth-child(4) {
  background-color: lch(from var(--base-color) l c calc(h + 270));
}

/* Use @supports to add in support old syntax that requires deg units
   to be specified in hue calculations. This is required for Safari 16.4+. */
@supports (color: lch(from red l c calc(h + 90deg))) {
  .tetradic :nth-child(2) {
    background-color: lch(from var(--base-color) l c calc(h + 90deg));
  }

  .tetradic :nth-child(3) {
    background-color: lch(from var(--base-color) l c calc(h + 180deg));
  }

  .tetradic :nth-child(4) {
    background-color: lch(from var(--base-color) l c calc(h + 270deg));
  }
}

/* Monochrome colors */
/* Base color, and base color with lightness channel -20, -10, +10, and +20 */

.monochrome :nth-child(1) {
  background-color: lch(from var(--base-color) calc(l - 20) c h);
}

.monochrome :nth-child(2) {
  background-color: lch(from var(--base-color) calc(l - 10) c h);
}

.monochrome :nth-child(3) {
  background-color: var(--base-color);
}

.monochrome :nth-child(4) {
  background-color: lch(from var(--base-color) calc(l + 10) c h);
}

.monochrome :nth-child(5) {
  background-color: lch(from var(--base-color) calc(l + 20) c h);
}

/* Hide unused swatches for each palette type */
.comp :nth-child(2) ~ div,
.triadic :nth-child(3) ~ div,
.tetradic :nth-child(4) ~ div {
  display: none;
}
關於 @supports 測試的旁註

在示例 CSS 中,你會注意到使用了 @supports 塊,為支援相對顏色語法早期規範草案的瀏覽器提供了不同的 background-color 值。這是必需的,因為 Safari 的初始實現是基於一箇舊版本的規範,其中源顏色通道值根據上下文解析為 <number> 或其他單位型別。這意味著在進行加減法時,值有時需要單位,這造成了混淆。在較新的實現中,源顏色通道值總是解析為等效的 <number> 值,這意味著計算總是使用無單位的值完成。

請注意,每種情況下的支援測試都是使用任意的顏色宣告來完成的——例如 color: lch(from red l c calc(h + 90deg))——不一定是我們需要為其他瀏覽器改變的實際值。當測試像這樣複雜的值時,你應該使用包含你想要測試的語法差異的最簡單的宣告。

@supports 測試中包含自定義屬性是行不通的——無論自定義屬性被賦予什麼值,測試結果總是為正。這是因為自定義屬性值只有在被賦值為常規 CSS 屬性的無效值(或無效值的一部分)時才會變得無效。為了解決這個問題,我們在每個測試中都用 red 關鍵字替換了 var(--base-color)

JavaScript

在 JavaScript 中,我們

  • 為單選按鈕新增一個 change 事件監聽器,以便當選擇一個按鈕時,執行 setContainer() 函式。該函式會用所選單選按鈕的值更新 ID 為 container<div>class 值,從而為子 <div> 應用所選調色盤型別的正確背景顏色。
  • 為顏色選擇器控制元件新增一個 input 事件監聽器,以便當選擇一個新顏色時,執行 setBaseColor() 函式。該函式將 --base-color 自定義屬性的值設定為新顏色。
js
const form = document.forms[0];
const radios = form.elements["palette-type"];
const colorPicker = form.elements["color"];
const containerElem = document.getElementById("container");

for (const radio of radios) {
  radio.addEventListener("change", setContainer);
}

colorPicker.addEventListener("input", setBaseColor);

function setContainer(e) {
  const palType = e.target.value;
  console.log("radio changed");
  containerElem.setAttribute("class", palType);
}

function setBaseColor(e) {
  console.log("color changed");
  containerElem.style.setProperty("--base-color", e.target.value);
}

結果

輸出如下。這開始展示了相對 CSS 顏色的強大之處——我們定義了多種顏色並生成了調色盤,這些調色盤可以透過調整單個自定義屬性來即時更新。

即時 UI 配色方案更新器

這個例子展示了一個包含標題和文字的卡片,但有一個特別之處——卡片下方有一個滑塊(<input type="range">)控制元件。當它的值改變時,JavaScript 會將 --hue 自定義屬性的值設定為新的滑塊值。

這反過來會調整整個 UI 的配色方案

  • --base-color 值是一個相對顏色,其色相通道被設定為 --hue 的值。
  • 設計中使用的其他顏色都是基於 --base-color 的相對顏色。因此,當 --base-color 改變時,它們也會改變。

HTML

示例的 HTML 如下所示。

  • <main> 元素作為一個外部包裝器來包含其餘內容,使得卡片和表單作為一個整體在 <main> 內部垂直和水平居中。
  • <section> 元素包含定義卡片內容的 <h1><p> 元素。
  • <form> 元素包含(<input type="range">)控制元件及其 <label>
html
<main>
  <section>
    <h1>A love of colors</h1>
    <p>
      Colors, the vibrant essence of our surroundings, are truly awe-inspiring.
      From the fiery warmth of reds to the calming coolness of blues, they bring
      unparalleled richness to our world. Colors stir emotions, ignite
      creativity, and shape perceptions, acting as a universal language of
      expression. In their brilliance, colors create a visually enchanting
      tapestry that invites admiration and sparks joy.
    </p>
  </section>
  <form>
    <label for="hue-adjust">Adjust the hue:</label>
    <input
      type="range"
      name="hue-adjust"
      id="hue-adjust"
      value="240"
      min="0"
      max="360" />
  </form>
</main>

CSS

在 CSS 中,:root 上設定了一個預設的 --hue 值,使用相對 lch() 顏色來定義配色方案,還有一個填充整個 body 的徑向漸變。

相對顏色如下

  • --base-color:基礎顏色以 red 為源顏色(儘管任何全綵色都可以),並將其色相值調整為 --hue 自定義屬性中設定的值。
  • --bg-color--base-color 的一個更亮的變體,旨在用作背景。它是透過以 --base-color 為源顏色並在其亮度值上加 40 來建立的。
  • --complementary-color:一個與 --base-color 在色輪上相差 180 度的互補色。它是透過以 --base-color 為源顏色並在其色相值上加 180 來建立的。

現在看看其餘的 CSS,並注意所有使用這些顏色的地方。這包括背景邊框text-shadow,甚至滑塊的 accent-color

備註: 為簡潔起見,只顯示了與相對顏色用法相關的 CSS 部分。

css
:root {
  /* Default hue value */
  --hue: 240;

  /* Relative color definitions */
  --base-color: lch(from red l c var(--hue));
  --bg-color: lch(from var(--base-color) calc(l + 40) c h);
  --complementary-color: lch(from var(--base-color) l c calc(h + 180));

  background: radial-gradient(ellipse at center, white 20%, var(--base-color));
}

/* Use @supports to add in support for --complementary-color with old
   syntax that requires deg units to be specified in hue calculations.
   This is required for in Safari 16.4+. */
@supports (color: lch(from red l c calc(h + 180deg))) {
  body {
    --complementary-color: lch(from var(--base-color) l c calc(h + 180deg));
  }
}

/* Box styling */

section {
  background-color: var(--bg-color);
  border: 3px solid var(--base-color);
  border-radius: 20px;
  box-shadow: 10px 10px 30px rgb(0 0 0 / 0.5);
}

h1 {
  background-color: var(--base-color);
  text-shadow:
    1px 1px 1px var(--complementary-color),
    -1px -1px 1px var(--complementary-color),
    0 0 3px var(--complementary-color);
}

/* Range slider styling */

form {
  background-color: var(--bg-color);
  border: 3px solid var(--base-color);
}

input {
  accent-color: var(--complementary-color);
}

JavaScript

JavaScript 為滑塊控制元件添加了一個 input 事件監聽器,以便當設定新值時,執行 setHue() 函式。該函式會在 :root(即 <html> 元素)上設定一個新的內聯 --hue 自定義屬性值,從而覆蓋我們在 CSS 中設定的原始預設值。

js
const rootElem = document.querySelector(":root");
const slider = document.getElementById("hue-adjust");

slider.addEventListener("input", setHue);

function setHue(e) {
  rootElem.style.setProperty("--hue", e.target.value);
}

結果

輸出如下所示。此處正在使用相對 CSS 顏色來控制整個 UI 的配色方案,該方案可以透過修改單個值來即時調整。

另見