使用相对颜色

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 的配色方案,该方案可以通过修改单个值来实时调整。

另见