采用 Baseline CSS 功能的色彩主题

David A. Herron
David A. Herron

发布时间:2025 年 12 月 11 日

因此,您有一个想要构建或重新设计的网站。您可能已经想好了一些核心颜色,并正在考虑如何根据这些颜色快速实现主题。

您不仅需要主色,还需要用于操作、悬停状态、错误和其他界面需求的颜色。那么浅色模式和深色模式选项呢?突然之间,您会发现自己需要很多颜色,这可能会让您感到不知所措。

好消息是,在构建与定义网站的颜色令牌相关的调色板以及在颜色模式之间切换时,Baseline 功能可以为您完成许多繁重的工作。您可以在精选演示中探索其中一些技巧,该演示是虚构的 Baseline Radio 网站上的一个以颜色为主题的播放列表。

使用相对颜色构建基础

如果您对主题的主要颜色有想法,那么借助一些基本的色彩理论和 CSS 相对颜色语法,您可以快速开始生成要在主题中使用的调色板。

假设您的基准颜色是某种色调的蓝绿色,您可以先以自己喜欢的颜色格式定义该颜色。然后,您可以使用任何颜色函数来创建相对于基色的新颜色:

html {
  --base-color: oklch(43.7% 0.075 224);
}

--base-color 自定义属性是使用 oklch() 颜色函数创建的。OkLCh 是 Oklab 颜色空间的圆柱形形式,可为三个通道定义值:L(明度)、C(色度)、H(色调),以及用于控制透明度的可选 Alpha 通道。

对于此类颜色操作,OkLCh 是一种不错的格式,因为它旨在提供感知均匀性。例如,如果您仅调整某种颜色的色调,所得颜色应具有与原始颜色相似的感知明度和色度。这对于避免出现意外的对比度问题尤为有用。

在保持与 --base-color 相同的明度和色度的前提下,您可以将色调在两个方向上调整 120 度,以获得三色调色板。

html {
  /* ... */
  --triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120));
  --triadic-color-secondary: oklch(from var(--base-color) l c calc(h - 120));
}

如图所示,相对颜色语法使用一个颜色函数,该函数通过 from 关键字引用源颜色(本例中为 --base-color),并根据所选的输出颜色(在本例中也将为 OkLCh)调整颜色空间的相应通道。

生成的输出会为您提供 --accent-color 的深粉色和 --highlight-color 的金色阴影,这两者的明度和色度都与原始 --base-color 相同。

html {
  /* ... */
  --accent-color: var(--triadic-color-primary);
  --highlight-color: var(--triadic-color-secondary);
}

  html {
    /* Input color in the rgb color space*/
    --base-color: teal;

     /* Output color in oklch. Computes to oklch(0.543123 0.0927099 314.769) */
     --triadic-color-primary: oklch(from var(--base-color) l c calc(h + 120));
  }

互补色会在色调角度上增加 180 度。

html {
  /* ... */
  --complement-color: oklch(from var(--base-color) l c calc(h + 180));
  --border-highlight: var(--complement-color);
}

对于界面中的悬停状态,您可能希望输出特定颜色的较浅版本。这意味着增加亮度通道的值。对于活跃状态,您可能需要通过调整 Alpha 通道来添加透明度,或者通过降低亮度通道的值来调暗颜色。

html {
  /* Darken the --base-color by 15% */
  --base-color-darkened: oklch(from var(--base-color) calc(l * 0.85) c h);
  /* Assign this color a meaningful variable name */
  --action-color: var(--base-color-darkened);
  /* Lighten the --action-color by 15% */
  --action-color-light: oklch(from var(--action-color) calc(l * 1.15) c h);
  /* Darken the --action-color by 10% */
  --action-color-dark: oklch(from var(--action-color) calc(l * 0.9) c h);
}

在此示例中,我们从 --base-color 派生出 --action-color,并将其用于按钮和链接。--action-color 有两种变体(较浅和较深),即使 --action-color 更改为相对于不同于 --base-color 的另一种颜色,这两种变体仍适用。

您可以使用 calc() 等数学函数调整渠道,也可以使用新值完全替换渠道。未更改的渠道由其各自的字母表示(例如,l 表示未更改的亮度值)。

使用 color-mix() 混合颜色

对于其他颜色变体,您可以采用类似的方法,调整 --base-color 自定义属性的其他渠道。您也可以使用 color-mix() 为设计的其他方面添加一些基色。

--border-color 是基础颜色和具名颜色 grey 的混合色,在 oklab 色彩空间中进行插值。用作颜色插值方法时,此方法可提供感知上均匀的结果。

html {
  --base-mix-grey-50: color-mix(in oklab, var(--base-color), grey);
  --border-color: var(--base-mix-grey-50);
}

默认情况下,每种颜色的权重均为 50%,但您可以调整百分比权重,使任一颜色更加突出或不那么突出。

html {
  --background-mix-base-80: color-mix(in oklab,
    var(--background-color) 80%,
    var(--base-color));
  --surface-light: var(--background-mix-base-80);
}

除了为元素添加更多颜色之外,还可以使用相对颜色语法调整元素的色度通道。当联系表单中的文本输入框处于聚焦状态时,其边框的颜色会略微鲜艳一些。

[data-input*="text"] {
  --focus-ring: transparent;
  /* ... */
  &:focus {
    --focus-ring: oklch(from var(--border-color) l calc(c + 0.1) h);
  }
}

选择启用浅色模式和深色模式

确定要使用的颜色集后,您需要一种高效的方式来为浅色模式和深色模式应用不同的颜色。

使用 color-scheme 属性表示对浅色主题和深色主题的支持

您可以使用 color-scheme 属性立即告知浏览器您的网站可以在“浅色”模式、“深色”模式或这两种模式下查看。此属性用于告知浏览器元素可以在哪些配色方案中舒适地呈现。

 html {
   color-scheme: light dark;
}

:root 伪元素或 html 元素上设置 color-scheme: light dark

  • 告知浏览器您的网页支持在浅色模式或深色模式下查看。
  • 更改浏览器界面的默认颜色,以匹配相应的操作系统设置。

为了让用户代理更早地注意到您的网页支持浅色和深色模式,您还可以通过在文档的 <head> 中添加 <meta> 元素来表明支持配色方案切换。

<head>
  <!-- ... -->
   <meta name="color-scheme" content="light dark">
</head>

使用 light-dark() 函数设置“浅色”和“深色”变体

作为作者,您可能习惯于使用 prefers-color-scheme @media 查询来设置网页的颜色。

@media (prefers-color-scheme: light) {
  html {
    --background-color: oklch(95.5% 0 162);
    --text-color: black;
  }
}

@media (prefers-color-scheme: dark) {
  html {
    --background-color: oklch(22.635% 0.01351 291.83);
    --text-color: white;
  }
}

这对于由作者控制的颜色和样式非常有效,但如上一部分所述,您仍然需要使用 color-scheme 来更新浏览器界面的颜色。

使用 prefers-color-scheme 查询更改网页颜色也意味着存在一些代码重复,因为您必须为每种模式分别定义颜色。

不过,如果为整个网页(或特定元素)设置了 color-scheme,您可以使用 light-dark() 函数在一行代码中为每种模式设置颜色。

该函数接受两种颜色。第一个用于将配色方案设置为“浅色”时,第二个用于将配色方案设置为“深色”时。

html {
  color-scheme: light dark;
  /* Color custom property values for both light and dark modes */
  --base-color: light-dark(oklch(43.7% 0.075 224), oklch(89.2% 0.069 224));
  --background-color: light-dark(oklch(95.5% 0 162), oklch(22.635% 0.01351 291.83));
  --accent-color: oklch(from var(--base-color) l c calc(h + 120));
  --active-color: light-dark(var(--action-color-light), var(--action-color-dark));
  /* ... */
}

与任何自定义属性一样,您可以全局设置或在特定组件中设置颜色的 light-dark(),然后根据需要在其他位置使用。

/* custom property usage */
body {
  background-color: var(--background-color);
  /* ... */
}

:any-link {
  /* ... */
  text-decoration-color: var(--accent-color);
}

通过内置主题切换器让用户掌控主题

主题能够适应用户的默认系统或浏览器颜色偏好设置,这固然很好,但您可以更进一步,让网站的观看者能够替换这些默认颜色偏好设置。

如果您构建了一个主题切换开关,用于更新 <html> 元素上的 data-scheme 属性,则可以使用同一属性通过 CSS 更改 color-scheme

html {
  color-scheme: light dark;

  &[data-scheme="light"] {
    color-scheme: light;
  }

  &[data-scheme="dark"] {
    color-scheme: dark;
  }

  &[data-scheme="green"] {
      --base-color-light: oklch(48.052% 0.11875 151.945);
      --base-color-dark: oklch(92.124% 0.13356 151.558);
      color-scheme: light dark;
   }
}

data-scheme="light"data-scheme="dark" 仅以各自的颜色模式显示网页。data-scheme="green" 可以在任一模式下查看,还会将 --base-color 更改为绿色阴影,从而为您提供全新的调色板,因为大多数其他颜色都基于 --base-color

使用 @property 注册自定义属性

到目前为止,演示中的颜色已设置为标准自定义属性。您还可以使用 @property 规则注册属性,以享受类型检查带来的好处。

由于 --base-color 用作界面中许多其他颜色的基础,因此最好确保它始终是一种颜色并具有回退值。

@property --base-color-light {
  syntax: '<color>';
  inherits: false;
  initial-value: oklch(43.7% 0.075 224);
}

@property --base-color-dark {
  syntax: '<color>';
  inherits: false;
  initial-value: oklch(89.2% 0.069 224);
}

html {
  --base-color: light-dark(var(--base-color-light), var(--base-color-dark));
}

这样一来,如果 --base-color 不慎更改为无效值,它始终会回退到通过 @property 规则设置的 initial-value

以这种方式注册某些属性还可以实现 linear-gradient() 中颜色的平滑动画效果。

.main-heading {
  background: linear-gradient(in oklch 90deg, var(--text-color) 50%, oklch(from var(--base-color) l c var(--header-hue)));
  background-clip: text;
  color: transparent;
  animation: header-hue-switch 5s ease-in-out infinite alternate;
}

.main-heading 具有 linear-gradient() 背景,该背景通过 background-clip 属性显示的透明文本显示出来。

部分文本显示了 hue,该元素使用相对颜色语法,从通道值 26.67 动画化为 277

@keyframes header-hue-switch {
  from {
    --header-hue: 26.67;
  }

  to {
    --header-hue: 277;
  }
}

注册 --header-hue 自定义属性后,由于浏览器知道此自定义属性是数字,因此可以顺利实现此动画。

@property --header-hue {
  syntax: '<number>';
  inherits: false;
  initial-value: 100;
}

如果自定义属性未注册,浏览器将不知道 --header-hue 的数据类型,因此向数字的过渡将是离散动画,即在状态之间跳跃,而不会进行平滑的插值。

小结

借助新的 Baseline 工具,您可以快速构建可调整的调色板,并更高效地创建颜色变量。不过,您仍然需要自行从无数种颜色选项和组合中做出选择。

这样动态创建调色板可让您灵活地进行操作。如果您需要更改品牌推广的基本颜色,只需更新 --base-color,其余主题颜色将随之变化。或者,如果您添加了音乐播放功能,则可以决定动态更改基本颜色以匹配当前播放的歌曲。

赠金

主题切换器逻辑改编自 Adam Argyle 的主题切换组件