我们不久前发布 了关于原生 CSS 变量(自定义属性)和预处理器变量之间区别的文章。 预处理器变量可以做一些原生变量做不到的深奥的事情,但总的来说,原生变量可以做同样的事情。 但是,由于它们的实时插值方式,它们更强大。 如果它们的值发生变化(例如 JavaScript、媒体查询命中等),更改会立即触发网站上的更改。
很酷,对吧? 但仍然,这实际上有多有用? 主要用例是什么? 我认为我们仍在努力找出答案。
我想,一个用例是网站主题(比如:网站周围元素的自定义颜色)。 而不是为一堆不同的主题编写不同的 CSS,或者编写 JavaScript 来定位我们要更改的所有元素并更改它们,我们只需编写一组基本 CSS 来使用变量,并将这些变量设置为主题颜色。
想象一下,我们允许自定义网站的页眉和页脚背景。
header {
background: var(--mainColor);
}
...
footer {
background: var(--mainColor);
}
可能有一个子标题,使用该颜色的深色变体。 以下是一个在另一个颜色之上叠加透明颜色层的技巧
.subheader {
background:
/* Make a bit darker */
linear-gradient(
to top,
rgba(0, 0, 0, 0.25),
rgba(0, 0, 0, 0.25)
)
var(--mainColor);
}
--mainColor
从哪里来?
使用主题,想法是您向用户询问它。 幸运的是,我们有颜色输入
<input type="color">
您可以将该值存储在数据库或您想要的任何其他存储机制中。 这是一个小的演示,其中该值存储在 localStorage 中
该值从 localStorage
中取出,并在页面加载时使用。 如果该值不存在,还会设置一个默认值(在 CSS 中)。
对我来说,上面的演示之所以引人入胜,是因为代码量很少。 将其维护为网站上的功能主要是 CSS 工作,并且似乎足够灵活,可以经受住时间的考验(可能)。
不出所料,我在这个方面落后了。
许多人认为主题是 CSS 自定义属性的主要用例之一。 让我们看看其他一些人的示例。
Giacomo Zinetti 有类似的颜色选择器实现
Harry Roberts 的示例和建议
他写了“使用自定义属性进行务实、实用和渐进式主题设计”,他在其中指出了像 Twitter 和 Trello 这样的应用程序,它们直接为用户提供主题设计

Harry 做了很多咨询工作,令我惊讶的是,他发现自己经常与想要这样做很多的企业合作。 他警告说
在大多数情况下,主题设计完全是一个锦上添花的功能。 它不是业务关键,通常甚至不重要。 如果有人要求您提供这样的主题设计,请不要以牺牲性能或代码质量为代价来实现它。
在 Sass 中 / 在 React 中
在通过自定义属性进行主题设计的真实应用程序中,Dan Bahrami 讲述了他们如何在 Geckoboard 上做到的,这是他正在开发的产品

这是一个 React 产品,但他们没有使用任何 JavaScript 中的样式,因此他们选择使用自定义属性(通过 Sass)来进行主题设计。
@mixin variable($property, $variable, $fallback) {
#{$property}: $fallback;
#{$property}: var($variable);
}
因此,他们可以执行以下操作
.dashboard {
@include variable(background, --theme-primary-color, blue);
}
这编译成具有回退
.dashboard {
background: blue;
background: var(--theme-primary-color);
}
他们还创建了 react-custom-properties,它完全是关于将自定义属性应用于组件,利用了您可以将自定义属性设置为内联样式的事实
<div style="--theme-primary-color: blue;">
</div>
不止一种颜色和属性
不仅颜色可以更改,自定义属性可以是任何有效值。 以下是由 Keith Clark 提供的演示,其中包含多种颜色和字体大小
David Darnes 在 Jekyll 网站中内置了主题设计
Microsoft 演示
Greg Whitworth 创建了这个演示(现在已下线,抱歉)

它使用颜色函数本身中的颜色修饰符
.distant-building__window {
fill: rgb(
calc(111 + (111 * var(--building-r-mod))),
calc(79 + (79 * var(--building-g-mod))),
calc(85 + (85 * var(--building-b-mod)))
);
}
这在所有浏览器中都不受支持。
Greg 还指出,CSS4 颜色函数(我们之前讨论过)将使所有这些主题设计功能更加强大。
Polymer 项目通过自定义属性进行主题设计
至少它在 v1 文档中是这样做的。 想法是,您将拥有一个 Web 组件,例如
<iron-icon icon="[[toggleIcon]]">
</iron-icon>
它具有智能默认值,但专门构建为允许通过主题进行样式设计
<style>
iron-icon {
fill: var(--icon-toggle-color, rgba(0,0,0,0));
stroke: var(--icon-toggle-outline-color, currentcolor);
}
:host([pressed]) iron-icon {
fill: var(--icon-toggle-pressed-color, currentcolor);
}
</style>
这意味着您可以设置这些变量,并使该组件采用新的颜色。
支持和回退
最近的支持情况已经相当不错了
此浏览器支持数据来自 Caniuse,该网站提供了更多详细信息。 数字表示浏览器在该版本及更高版本中支持该功能。
桌面
Chrome | Firefox | IE | Edge | Safari |
---|---|---|---|---|
49 | 31 | 否 | 16 | 10 |
移动设备/平板电脑
Android Chrome | Android Firefox | Android | iOS Safari |
---|---|---|---|
127 | 127 | 127 | 10.0-10.2 |
Opera Mini 和 IE 尤其缺失。 我们已经讨论过在使用自定义属性之前设置有效的非变量属性作为回退的想法。
就像许多现代 CSS 功能一样,您可以使用 @supports
在使用之前测试支持情况
@supports (--color: red) {
:root {
--color: red;
}
body {
color: var(--color);
}
}
这始终取决于具体情况,但在 CSS 中,将回退放在之前的声明上可能是处理不支持情况最有效的方法。 还有边缘情况。
Michael Scharnagl 文档 中记录了一种用于测试的 JavaScript 方法
if (window.CSS && window.CSS.supports && window.CSS.supports('--a', 0)) {
// CSS custom properties supported.
} else {
// CSS custom properties not supported
}
颜色和无障碍
在为文本设置颜色以及文本后面的颜色时,这些颜色之间的对比度是一个无障碍问题。 对比度过低,难以阅读。
一个比较常见的解决方案是根据后面的颜色来选择文本是浅色还是深色(白色或黑色)。
David Halford 使用 JavaScript 演示了如何计算此对比度
Brendan Saunders 使用 Sass 演示了如何计算此对比度
有人研究过使用超过少量自定义属性的性能影响吗? 我想在下一个项目中使用它们,但如果它们在规模上变得卡顿,就很难说服他们。
使用自定义属性设置单个属性总是比操作每个需要自定义样式的 DOM 节点的样式要快。
快近 100 倍:https://jsperf.com/css-variables-vs-inline-styles
我不太明白这部分内容。
所有
@supports
做的只是对解析器级别支持进行检查,链接的版本工作正常。此外,CSS.supports()
方法实际上使用与@supports
相同的底层代码,因此它与在 CSS 中声明式使用它相同。这仍然可以用来确定浏览器是否支持自定义属性,因为如果它无法解析它,它就会失败。我修复了那部分!我读了这个,然后就感觉,天哪,这真是太奇怪了。但我猜这都是关于将一个变量设置为另一个变量吗?
@chriscoyier
是的,它可能有点令人困惑,但变量存在与否无关紧要,请记住,你只是测试解析器是否支持自定义属性,而不是级联和其他自定义属性因素的能力。我在文章的“检测对自定义属性的支持”部分介绍了这一点。你实际上可以执行以下操作,它具有自解释性
这里有一个jsbin,以及上面内容的截图,使用的是Edge/IE11
希望这有助于澄清。
@chriscoyier
另外,感谢你提到了演示。由于我注意到你使用的是存在 calc() 问题的浏览器,因此我在twitter上发布了它的运行 gif。我还想指出,虽然是我做了编码工作,但所有出色的设计工作都是由 Stephanie Drescher 完成的 :)
用于使
--mainColor
变暗的“小技巧”非常棒,我打算毫不羞耻地“偷”它。我一直在一个小项目中使用 CSS 变量,并且一直在选择调色板,而这简化了所有操作。可惜你不能将相同的技术应用于自动调整文字颜色。
我也很喜欢使颜色变暗的技巧!谢谢 Chris!
昨天我构建了一个使用自定义属性功能的代码片段生成器。大家可以看看
https://pawelgrzybek.com/snippet-generator/
几个月前,我还利用它创建了一个新的颜色切换器。
演示
http://codepen.io/pawelgrzybek/pen/KVLmXQ
文章
https://pawelgrzybek.com/css-custom-properties-explained/
嘿,Chris,
很荣幸在 CSS-Tricks 文章中被提及!感谢你的认可。你可能感兴趣的是,React 16 将支持直接在元素的
style
属性中设置自定义属性。例如…<div style={{ ‘--my-color’ : ‘red’}} />
很棒的文章,最近一直在尝试这些内容,有一些很酷的用例。
还值得一提的是,如果未设置变量,则会内置回退。
color: var(--text-color, black);
如果代码中不存在
--text-color
,则将默认设置为black
https://mdn.org.cn/en-US/docs/Web/CSS/var#Browser_compatibility
大约 8 个月前,我在我的作品集上使用了这个方法
http://jsil.work/
我使用 jQuery 将滑块元素连接到 HSL 中的色调值。然后在 SVG 和 CSS 元素中使用了这个变量。
非常感谢你的文章,我使用的几乎所有代码都是从 CSS Tricks 中挖掘出来的。
我想将它应用到我的 WordPress 模板中,我的想法是像这篇文章一样写入本地存储,并使用自定义程序 API 保存到数据库中。
这样用户可以即时看到他们的更改。有人能看到这种方法有什么问题吗?这将使我的 WP 网站对我的客户来说更灵活,但仍然保留所有 WP 的优势。
所以我做到了,
没有使用本地存储,因为自定义程序 API 有自己的预览回调。不得不承认,能够看到颜色和字体从自定义程序中更改真是太神奇了。它超级流畅,而且我为 IE 等设置了 Sass 回退。
我的工作流程如下
1. 在 WordPress 自定义程序中设置新字段
2. 设置 js 预览 postMessage 回调 - 查看这篇文章
https://code.tutsplus.com/tutorials/customizer-javascript-apis-getting-started–cms-26838
3. 将保存的字段写入 admin-ajax 变量。
4. 在页面加载时设置这些变量
注意 - 如果你不想让人看到颜色变化,你需要实现一个预加载器(我更喜欢异步设置 css 变量)。
Stephanie Liu 的文章和演示很棒
http://ramenhog.com/blog/2017/06/07/theming-with-css-custom-properties