使用 CSS 自定义属性使您的 CSS 动态化

已发表: 2022-03-11

如果您已经编写 CSS 有一段时间了,那么您一定在某个时间点感到需要变量。 CSS 自定义属性有点像 CSS 自己的变量实现。 但是,如果使用得当,它们可以不仅仅是变量。

CSS 自定义属性允许您:

  • 为具有您选择的名称的属性分配任意值
  • 使用var()函数在其他属性中使用这些值

尽管目前对 CSS 自定义属性的支持有点困难,并且一些浏览器在需要预先激活或设置为 true 的标志下支持它们,但预计它们的支持会在未来急剧增加,因此了解这一点很重要如何使用和利用它们。 1

使用 CSS 自定义属性

在本文中,您将了解如何使用 CSS 自定义属性使您的样式表更具动态性,也许会使资产管道中的额外 Sass/LESS 步骤过时。

原始且功能较弱的 CSS 变量

在开始讨论 CSS 自定义属性之前,需要注意的是,很长一段时间以来,CSS 都有一个变量,那就是currentColor关键字。 这个很少使用但被广泛支持的变量,指的是元素的当前颜色值。 它可以用于任何接受color值的声明,并且可以完美地级联。

我们来看一个例子:

 .element { color: blue; border: 2px solid currentColor; /* Sets a solid, 2px wide, blue border to the element */ }

除了级联之外,这还可以产生以下内容:

 .element span { background: currentColor; /* Sets a blue background color for every span child of .element, unless a color property is declared in this same block */ } .element span.red { color: red; /* Sets a red background color for every span child of .element that has the class .red, since currentColor is applied to the background of every span child of .element no matter if they have the .red class or not */ }

currentColor的主要问题,除了它本身没有作为变量在规范中之外,它只接受 color 属性的值,这在某些情况下可能难以使用。

成熟的 CSS 变量

使用 CSS 预处理器/后处理器的主要优点之一是它们允许将值存储在关键字中,并在必要时将它们限定为某个选择器。

在开发人员长期要求之后,编写了一份解释 CSS 原生变量的草案。 这些正式称为 CSS 自定义属性,但有时也称为 CSS 变量。

本机 CSS 自定义属性的当前规范涵盖了与前/后处理器变量相同的所有行为。 这使您能够存储颜色代码、具有所有已知单位的尺寸,或者在需要时仅存储整数(例如,当您需要使用相同的除数或乘数时)。

CSS 自定义属性的语法与其他语言相比有点奇怪,但如果将它们的语法与同一个 CSS 生态系统中的其他功能进行比较,它就会很有意义:

 :root { --color-black: #2e2e2e; } .element { background: var(--color-black); }

现在,您可能会想:“那是什么语法!?”

好吧,Lea Verou 以绝对简单的方式解释了这种“破折号”语法的原因,正如她在她精彩的演讲 CSS 变量:var(–subtitle) 中所说:

它们的工作方式与任何其他 CSS 属性 [...] 完全相同。 很多人问我为什么不使用美元 [符号] 或类似的东西,我们不使用美元 [符号] 的原因是我们希望人们能够同时使用 SASS 或预处理器变量和CSS 变量。 它们都是不同的东西,它们实现不同的目标,有些事情你可以用 CSS 变量做而你绝对不能用 SASS 做的事情,有些事情你可以用 SASS 变量做你不能用 CSS 变量做的事情,所以我们想要人们能够在同一个样式表中同时使用它们,因此您可以将破折​​号语法想象成带有空前缀的前缀属性。

我们可以使用var()函数检索自定义属性的值,除了选择器、属性名称或媒体查询声明之外,我们可以在任何地方使用它。

值得注意的是,虽然前/后处理器变量仅在编译时使用,但 CSS 变量可以动态使用和更新。 这是什么意思? 这意味着它们被保留在实际的 CSS 样式表中。 因此,即使在样式表被编译后,它们是变量的概念仍然存在。

为了更清楚,让我用一些例子来说明情况。 以下代码块是 SASS 样式表的一部分:

 :root { $value: 30px; } @media screen and (min-width: 768px) { $value: 60px; } .corners { border-radius: $value; }

这个 SASS 声明和规则片段编译成 CSS 如下:

 .corners { border-radius: 30px; }

您可以看到:rootmedia查询中的属性在编译后都丢失了,因为 SASS 变量不能存在于 CSS 文件中(或者,更准确地说,它们可以强制存在于 CSS 文件中,但被忽略因为它们的一些语法是无效的 CSS),所以变量的值不能在之后更新。

现在让我们考虑相同的情况,但仅使用 CSS 变量而不应用 CSS 预处理器/后处理器(即,不执行任何编译或编译):

 :root { --value: 30px; } @media screen and (min-width: 768px) { --value: 60px; } .corners { border-radius: var(--value); }

显然,没有任何变化,因为我们没有编译/转译任何东西,并且自定义属性的值可以动态更新。 因此,例如,如果我们使用 JavaScript 之类的东西更改--value的值,则该值将在使用 var() 函数调用它的每个实例中更新。

自定义属性的功能使此功能如此强大,您甚至可以执行自动前缀等操作。

Lea Verou 使用clip-path属性设置了一个示例。 我们首先将要添加前缀的属性的值设置为initial但使用自定义属性,然后继续将每个前缀属性的值设置为自定义属性值:

 * { --clip-path: initial; -webkit-clip-path: var(--clip-path); clip-path: var(--clip-path); }

在此之后,剩下的就是更改选择器中自定义属性的值:

 header { --clip-path: polygon(0% 0%, 100% 0%, 100% calc(100% - 2.5em), 0% 100%); }

如果您想对此了解更多,请查看 Lea 关于使用 CSS 变量进行自动前缀的完整文章。

防弹 CSS 自定义属性

如前所述,浏览器对 CSS 自定义属性的支持在很大程度上仍然是非标准的。 那么如何克服呢?

这就是 PostCSS 及其插件 postcss-css-variables 发挥作用的地方。

如果您想知道 PostCSS 是什么,请查看我的文章 PostCSS:SASS 的新播放日期,并在完成后返回此内容。 然后,您将对使用这个神奇的工具可以做什么有一个基本的了解,并且在阅读本文的其余部分时不会感到迷失方向。

使用postcss-css-variables插件,并将其preserve选项设置为 true,我们可以将所有var()函数声明保留在输出中,并将计算值作为后备声明。 它还保留计算的--var声明。 请记住,使用这个 PostCSS 插件,自定义属性可以在转换过程之后动态更新,但回退值将保持不变,除非它们是专门针对并单独显式更改的。

如果您正在寻找一种无需预处理器/后处理器的方式来使用 CSS 变量,您始终可以使用 CSS @support规则手动检查当前支持,并在支持不完整或不存在时应用适当的回退。 例如:

 :root { --color-blue: #1e90ff; /* hex value for dodgerblue color */ } .element { background: var(--color-blue); } @supports (not(--value: 0)) { /* CSS variables not supported */ .element { background: dodgerblue; } }

使用 JavaScript 更改自定义属性的值

在整篇文章中,我一直在提到可以使用 JavaScript 更新变量,所以让我们开始吧。

假设你有一个浅色主题并想将其切换为深色主题,假设你有一些如下所示的 CSS:

 :root { --text-color: black; --background-color: white; } body { color: var(--text-color); background: var(--background-color); }

您可以通过执行以下操作来更新--text-color--background-color自定义属性:

 var bodyStyles = document.body.style; bodyStyles.setProperty('--text-color', 'white'); bodyStyles.setProperty('--background-color', 'black');

有趣的用例

经过多年关于 CSS 自定义属性规范的开发和讨论,出现了一些有趣的用例。 这里有一些例子:

主题:在实现 CSS 变量时,为网站使用一组主题相当容易。 想要您当前风格的浅色或深色变化吗? 只需使用 JavaScript 更改一些自定义属性的值即可。

间距调整:需要微调站点的间距,比如列之间的排水沟? 更改单个 CSS 变量的值并查看此更改在站点范围内的反映。

完全动态的 calc() 函数:现在您可以在这些函数中使用自定义属性来拥有完全动态的calc()函数,无需在 JavaScript 中进行复杂或短暂的计算,然后在每个实例上手动更新这些值。

为您的 CSS 文件注入新的活力

CSS 自定义属性是一种强大且创新的方式,可为您的样式表带来更多活力,它首次在 CSS 中引入了完全动态的值。

该规范目前处于候选推荐状态,这意味着标准化指日可待,这是深入研究此功能并充分利用它的好理由。

  1. 注意:正如 Lea Verou 在 4 月 22 日指出的那样,现在几乎所有主流浏览器都默认支持自定义属性,而无需切换标志。 除非需要对旧浏览器版本的支持,否则它在生产中的使用是安全的。