从内部范围覆盖 :root CSS 变量 [英] Overriding :root CSS variables from inner scopes
问题描述
在 Stack Overflow 的设计系统中,我们使用 Less 来编译 CSS 颜色值.
我们有全局 Less 变量,例如 @orange-500
,它们经常针对悬停状态、构建边框样式、背景颜色等进行修改.
在 Less 中,这被写成 darken(@orange-500, 5%)
.我正在尝试使用本机 CSS 变量实现类似的功能.切换到 CSS 变量将使我们能够更快地发布依赖主题(堆栈交换网络、暗模式等)的功能,使用更少的 CSS 行,同时在媒体查询上启用交换变量(高对比度、暗模式等).
这个在 hsl
中覆盖颜色亮度值的示例在变量范围限定为 CSS 类时起作用:
.card {--orange: hsl(255, 72%, var(--lightness, 68%));背景:var(--orange);}.card:悬停{--亮度:45%;}
你好,世界
然而,我们需要在一个单一的、可交换的地方全局指定我们的颜色变量以支持全局主题,但这并不能按预期工作:
:root {--orange: hsl(255, 72%, var(--lightness, 68%));}.卡片 {背景:var(--orange);}.card:悬停{--亮度:45%;}
你好,世界
我尝试从 :root
切换到 html
或 body
,但没有任何运气.对此有什么解决方法吗?
这是一个范围界定问题.你这样做的方式,你是从 :root
和 --orange
继承 --orange
在 :root
的亮度为 68%.
为了更改它,您需要将 --orange
变量的范围重新设置为将查找新的 --lightness
值的元素.有几种方法可以解决这个问题:
选项 1:复制元素上的 --orange
变量:
:root {--亮度:68%;--orange: hsl(255, 72%, var(--lightness));}.卡片 {背景:var(--orange);--orange: hsl(255, 72%, var(--lightness));}.card:悬停{--亮度:45%;}
你好,世界
显然这有点糟糕,因为您将不得不复制那个 --orange
变量.
选项 2:您可以抽象 --orange
的其他参数,以免重复.尽管文本更多,但我还是会喜欢这种方法:
:root {--亮度:68%;--orangeHue: 255;--orangeSat:72%;--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));}.卡片 {背景:var(--orange);--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));}.card:悬停{--亮度:45%;}
你好,世界
您可以还做的是将其范围专门用于可能应用于 HTML 元素或正文的 .darkMode
类.这也很有意义,因为从代码中可以清楚地看出意图是什么:
选项 3
:root {--亮度:68%;--orangeHue: 255;--orangeSat:72%;--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));}.卡片 {背景:var(--orange);}.card:悬停{--亮度:45%;}.darkMode .card {--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));}
<div class="card">你好,世界
不管你怎么走,问题是 --orange
变量是从其设置 --lightness
的原始范围继承的.将其视为继承计算值".
为了让 --orange
获得新的亮度,你需要一个新的 --orange
某处.
选项 4
我不确定您的主题模式是什么,但我可以解释我如何在自己的博客上创建暗模式 .如果你看看 CSS 什么你会看到我创建了两个遵循相同命名约定的完整主题:
--themeLightTextColor: rgb(55, 55, 55);--themeLightBGColor: rgb(255, 255, 255);--themeLightAccentColor: rgb(248, 248, 248);--themeLightTrimColor: rgb(238, 238, 238);--themeDarkTextColor: rgb(220, 220, 220);--themeDarkBGColor: rgb(23, 23, 23);--themeDarkAccentColor: rgb(55, 55, 55);--themeDarkTrimColor: rgb(40, 40, 40);
然后我要做的是创建一个第三组变量,它们的工作是成为主动"经理:
--themeActiveLinkColor: var(--linkColor);--themeActiveLinkColorHover: var(--linkColorHover);--themeActiveTextColor: var(--themeLightTextColor);--themeActiveEditorialTextColor: var(--themeLightPltNlow);--themeActiveBGColor: var(--themeLightBGColor);--themeActiveAccentColor: var(--themeLightAccentColor);--themeActiveTrimColor: var(--themeLightTrimColor);
然后,我将活动主题设置范围限定在一个类下:
.theme--dark {--themeActiveTextColor: var(--themeDarkTextColor);--themeActiveEditorialTextColor: var(--themeDarkPltNlow);--themeActiveBGColor: var(--themeDarkBGColor);--themeActiveAccentColor: var(--themeDarkAccentColor);--themeActiveTrimColor: var(--themeDarkTrimColor);}
似乎您的意图是不必显式声明主题,而是调整一些根变量"来调整它.但我建议您可能有一个模式,单个类可以更改活动主题.这种模式的优点是您还可以调整类名上的任何根变量".
In our design system at Stack Overflow, we use Less to compile CSS color values.
We have global Less variables like @orange-500
that are frequently modified for hover states, building border styling, background colors, etc.
In Less, this is written as darken(@orange-500, 5%)
. I'm trying to achieve something similar using native CSS variables. Switching to CSS variables will allow us to ship features that rely on theming (Stack Exchange Network, Dark Mode, etc.) much faster, with way fewer lines of CSS, while enabling swapping variables on media query (high contrast, dark mode, etc).
This example of overriding our color’s lightness value in hsl
works when the variables are scoped to a CSS class:
.card {
--orange: hsl(255, 72%, var(--lightness, 68%));
background: var(--orange);
}
.card:hover {
--lightness: 45%;
}
<div class="card">
Hello world
</div>
However, we need to specify our color variables globally in a single, swappable place to support global theming, but this doesn't work as expected:
:root {
--orange: hsl(255, 72%, var(--lightness, 68%));
}
.card {
background: var(--orange);
}
.card:hover {
--lightness: 45%;
}
<div class="card">
Hello world
</div>
I've tried switching from :root
to html
or body
without any luck. Any workarounds to this?
This is a scoping issue. The way you're doing it, you're inheriting --orange
from the :root
, and --orange
in the :root
has a lightness of 68%.
In order to change it, you'll want to re-scope the --orange
variable to an element that will look up the new --lightness
value. There's a few ways to pull this off:
Option 1: duplicate the --orange
variable on the element:
:root {
--lightness: 68%;
--orange: hsl(255, 72%, var(--lightness));
}
.card {
background: var(--orange);
--orange: hsl(255, 72%, var(--lightness));
}
.card:hover {
--lightness: 45%;
}
<div class="card">
Hello world
</div>
Obviously this kinda stinks, because you're going to have to duplicate that --orange
variable.
Option 2:
You could abstract the other parameters of --orange
so that it's not as duplicative. I'd be a fan of this approach despite the fact that it's more text:
:root {
--lightness: 68%;
--orangeHue: 255;
--orangeSat: 72%;
--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
.card {
background: var(--orange);
--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
.card:hover {
--lightness: 45%;
}
<div class="card">
Hello world
</div>
What you could also do is scope this specifically to a .darkMode
class that might be applied to the HTML element or the body. This could also make sense because it's clear what the intent is from the code:
Option 3
:root {
--lightness: 68%;
--orangeHue: 255;
--orangeSat: 72%;
--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
.card {
background: var(--orange);
}
.card:hover {
--lightness: 45%;
}
.darkMode .card {
--orange: hsl(var(--orangeHue), var(--orangeSat), var(--lightness));
}
<div class="darkMode">
<div class="card">
Hello world
</div>
</div>
Regardless of how you go, the issue is that the --orange
variable is inheriting from its original scope where --lightness
is set. Think of it as "inheriting a computed value".
In order to get --orange
to get the new lightness, you need a new --orange
somewhere.
Option 4
I'm not sure what your theme pattern is, but I can explain how I created a dark mode on my own blog . If you look at the CSS What you'll see is that I've created two complete themes that follow the same naming convention:
--themeLightTextColor: rgb(55, 55, 55);
--themeLightBGColor: rgb(255, 255, 255);
--themeLightAccentColor: rgb(248, 248, 248);
--themeLightTrimColor: rgb(238, 238, 238);
--themeDarkTextColor: rgb(220, 220, 220);
--themeDarkBGColor: rgb(23, 23, 23);
--themeDarkAccentColor: rgb(55, 55, 55);
--themeDarkTrimColor: rgb(40, 40, 40);
What I then do is create a third set of variables whose job it is to be the "active" managers:
--themeActiveLinkColor: var(--linkColor);
--themeActiveLinkColorHover: var(--linkColorHover);
--themeActiveTextColor: var(--themeLightTextColor);
--themeActiveEditorialTextColor: var(--themeLightPltNLow);
--themeActiveBGColor: var(--themeLightBGColor);
--themeActiveAccentColor: var(--themeLightAccentColor);
--themeActiveTrimColor: var(--themeLightTrimColor);
Then, I scope the active theme settings under a single class:
.theme--dark {
--themeActiveTextColor: var(--themeDarkTextColor);
--themeActiveEditorialTextColor: var(--themeDarkPltNLow);
--themeActiveBGColor: var(--themeDarkBGColor);
--themeActiveAccentColor: var(--themeDarkAccentColor);
--themeActiveTrimColor: var(--themeDarkTrimColor);
}
It seems like maybe your intent is to not have to explicitly declare a theme, but rather tweak some "root variables" to adjust it. But I would suggest that maybe you have a pattern in place where a single class can change an active theme. The advantage to this pattern is that you would be able to also adjust any "root variables" on the class name.
这篇关于从内部范围覆盖 :root CSS 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!