在 CSS 自定义属性(我们可能在本文中将其称为“变量”,因为这就是它们的本质)出现之前,在同一个网站上实现多个颜色方案通常意味着编写单独的样式表。这绝对不是世界上最易于维护的东西。然而,如今,我们可以在单个样式表中定义变量,并让 CSS 完成神奇的运算。
即使您没有提供诸如用户生成或用户选择的颜色主题之类的功能,您仍然可以在您的网站上使用主题的概念。例如,在网站的不同区域使用不同的颜色主题相当常见。
我们将构建一个类似于此的示例

在这个示例中,各部分之间唯一变化的是颜色**色调**;亮度的变化始终相同。以下是一个特定色调的简化色板示例
多个色调的色板可能看起来像这样
使用 RGB 颜色值来实现这将需要付出努力,但在 HSL 中,只有一个值发生变化。
输入自定义属性
自定义属性已经存在了一段时间,并且得到了广泛支持。填充 和 其他解决方案 可用于 IE 11。
语法与传统 CSS 非常相似。以下是对基本用法的概述
通常在:root
伪元素上定义变量,该元素在 HTML 中始终是<html>
,但具有更高的特异性。也就是说,变量可以在任何元素上定义,这对于将特定变量的作用域限定到特定元素很有用。例如,以下是在数据属性上定义的变量
将 calc() 加入组合
变量不必是固定值。我们可以利用calc()
函数的功能,在遵循统一模式的同时自动为我们计算值
由于 CSS 不支持循环,预处理器将有助于生成一部分代码。但请记住:CSS 变量与 Sass 变量不同。
实现 CSS 变量
我们基本上要做的是在同一页面不同部分的同一个组件上更改颜色。就像这样
我们在选项卡中具有三个部分,它们有自己的 ID:#food
、#lifestyle
和 #travel
。每个部分对应于不同的色调。div.wrapper
元素上的data-theme-attribute
定义了当前使用的色调。
当#travel
是活动选项卡时,我们使用的是--first-hue
变量,其值为 180°。这就是在该部分上用作--hue
值的值,从而产生青绿色。
<div class="wrapper" data-theme="travel">
.wrapper[data-theme="travel"] {
--hue: var(--first-hue); /* = 180° = teal */
}
单击任何选项卡都会将 data-theme 属性更新为该部分的 ID,同时删除其散列(#
)。这需要一点 JavaScript。这是 CSS 的优点之一(很多):它们可以使用 JavaScript 进行访问和操作。这与预处理器变量大不相同,预处理器变量在构建阶段编译成值,不再可以在 DOM 中访问。
<li><a href="#food">Food</a></li>
const wrapper = document.querySelector('.wrapper');
document.querySelector("nav").addEventListener('click', e => {
// Get theme name from URL and ditch the hash
wrapper.dataset.theme = e.target.getAttribute('href').substr(1);
})
渐进增强
当我们使用 JavaScript 时,我们应该注意用户可能禁用了 JavaScript 的情况。否则,我们的脚本(以及我们的 UI 扩展)将无法访问。此代码段确保即使在这些情况下,网站内容仍然可以访问
// progressive enhancement:
// without JavaScript all sections are displayed, the theme is only set when the page loads
wrapper.dataset.theme = wrapper.querySelector('section').id;
这仅仅允许选项卡向上滚动页面到相应的部分。当然,主题消失了,但提供内容更为重要。
虽然我选择使用单页面方法,但也可以将这些部分作为单独的页面提供,并在服务器端设置[data-theme]
。
另一种方法
到目前为止,我们假设颜色值呈线性变化,因此可以采用数学方法。但即使在仅部分符合此假设的情况下,我们仍然可以从相同概念中获益。例如,如果亮度遵循某种模式,但色调不遵循,我们可以像这样拆分样式表
<head>
<style>
:root {
--hue: 260;
}
</style>
<link rel="stylesheet" href="stylesheet-with-calculations-based-on-any-hue.css">
</head>
支持 Web 组件
Web 组件 是一个令人兴奋(且不断发展)的概念。想象一下,我们可以拥有可以在任何地方重复使用并根据具体情况进行主题化的封装组件,这真是令人心动。一个组件,多种上下文!
我们可以将 CSS 变量主题与 Web 组件一起使用。这需要我们使用host-context()
伪选择器。(感谢 habemuscode 向我指出这一点!)
:host-context(body[data-theme="color-1"]) {
--shade-1: var(--outsideHSL);
}
总之…
使用 CSS 自定义属性对网站进行主题化比我们过去采用的变通方法要容易得多。它更易于维护(一个样式表)、更高效(更少的代码),并开辟了新的可能性(使用 JavaScript)。更不用说,当 CSS 自定义属性与 HSL 颜色和calc()
函数一起使用时,它们会变得更加强大。
我们只看了一个示例,其中我们可以根据组件使用的部分来更改组件的颜色主题。但再说一次,当我们开始涉及诸如让用户自行更改主题之类的功能时,这里还有更多机会——Chris 在这篇文章中探讨了这一主题。
如果您还希望调整黄色比其他颜色更亮,该怎么办?您可以根据色调添加某种调整因子吗?
色调 和 亮度 是相互独立的;我不明白您如何根据另一个来更改一个。如果您需要覆盖特定部分的色调,您可以这样做
--hue: calc(var(--first-hue) + calc(var(--hue-step) * 3) + 15); // 15 代表您的调整
要覆盖亮度,您需要在定义其他任何内容之前为每个部分设置
--lgt-step
。随时分叉代码笔并尝试一下。我对使用 CSS 变量的概念还比较陌生,但发现这个主题非常有趣。在哪里可以找到更完整的教程?我主要想能够设置和改变颜色色调和亮度值,并将它们应用于字体,例如标题、链接、文本部分的某些背景等。
点击最后一个笔的SCSS选项卡,我想这就是你想要的东西。
好的。我明白你的意思了。我采用了另一种方法
我像这样在:root中设置了变量
然后使用这些变量逐段用于 CSS 文件中更下层的元素的 hsl - 这全部在 custom.css 文件中完成,如下所示
这是自定义属性的正确用法。我可能会在
:root
中添加一些额外的属性,用于你可能更常使用的内容,例如然后在custom.css中使用
var(--text-color)
。顺便说一下,如果你在这里发布代码示例,你可以将它们放在一对三引号 (```) 中,以提高可读性,更多信息请点击这里。